Mẫu và đối sánh (3.0)
Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 87 trên 110.
Dart 3 giới thiệu so khớp mẫu, một cách mạnh mẽ để phân rã và kiểm tra dữ liệu trong một biểu thức. Mẫu cho phép bạn trích xuất giá trị từ các đối tượng, kiểm tra cấu trúc của chúng và gán giá trị cho các biến cùng lúc.
Bạn đã thấy cách phân rã cơ bản với record. Mẫu giúp mở rộng cách này để làm việc với đối tượng, danh sách và map:
void main() {
// Mẫu danh sách
var numbers = [1, 2, 3];
var [a, b, c] = numbers;
print('$a, $b, $c'); // 1, 2, 3
// Mẫu ánh xạ
var user = {'name': 'Alice', 'age': 30};
var {'name': name, 'age': age} = user;
print('$name is $age'); // Alice is 30
}Pattern trở nên đặc biệt mạnh mẽ trong các biểu thức switch. Bạn có thể đồng thời khớp theo kiểu, giá trị và cấu trúc:
String describe(Object obj) {
return switch (obj) {
int n when n < 0 => 'Negative number',
int n => 'Positive number: $n',
String s => 'String of length ${s.length}',
[int first, ...] => 'List starting with $first',
_ => 'Something else',
};
}
void main() {
print(describe(-5)); // Số âm
print(describe(42)); // Số dương: 42
print(describe([1, 2, 3])); // Danh sách bắt đầu bằng 1
}Mệnh đề when bổ sung điều kiện cho các mẫu, còn ... khớp với các phần tử còn lại trong danh sách. Dấu gạch dưới _ đóng vai trò là ký tự đại diện, khớp với mọi thứ. Khi kết hợp với các lớp sealed, mẫu cho phép xử lý đầy đủ và an toàn về kiểu đối với các cấu trúc dữ liệu phức tạp.
Thử thách
DễHãy xây dựng một bộ phân loại dữ liệu sử dụng tính năng khớp mẫu (pattern matching) để phân tích và phân loại nhiều kiểu đầu vào! Bạn sẽ tạo một hệ thống có thể nhận diện và mô tả nhiều cấu trúc dữ liệu bằng các tính năng khớp mẫu mạnh mẽ của Dart 3.
Bạn sẽ sắp xếp code thành hai tệp:
classifier.dart: Tạo một hàm có tênclassify, nhận tham sốObjectvà trả về phần mô tả kiểuString. Dùng biểu thức switch với tính năng khớp mẫu để xử lý các trường hợp sau:- Danh sách rỗng
[]sẽ trả vềEmpty list - Danh sách có đúng một phần tử số nguyên sẽ trả về
Single item: [value] - Danh sách có đúng hai phần tử sẽ trả về
Pair: [first] and [second] - Danh sách bắt đầu bằng một số nguyên, theo sau là các phần tử khác, sẽ trả về
List starting with [first], length: [total length](dùng mẫu phần còn lại...) - Từ điển chứa cả hai khóa
'name'và'age'sẽ trả về[name] is [age] years old(dùng phép phân rã bằng mẫu từ điển) - Số nguyên âm (dùng mệnh đề
when) sẽ trả vềNegative: [value] - Số nguyên bằng không sẽ trả về
Zero - Mọi số nguyên khác sẽ trả về
Positive: [value] - Mọi giá trị khác sẽ trả về
Unknown type
- Danh sách rỗng
main.dart: Nhập bộ phân loại và minh họa tính năng khớp mẫu với nhiều đầu vào. In ra kết quả phân loại từng giá trị sau:- Danh sách rỗng
[] - Danh sách có một phần tử:
[42] - Danh sách có hai phần tử:
['hello', 'world'] - Danh sách dài hơn:
[1, 2, 3, 4, 5] - Một từ điển:
{'name': 'Alice', 'age': 25} - Số nguyên
-10 - Số nguyên
0 - Số nguyên
99
- Danh sách rỗng
Thử thách này kết hợp mẫu danh sách, mẫu từ điển, mệnh đề when để kiểm tra điều kiện và mẫu phần còn lại (...), tất cả đều là những tính năng khớp mẫu chính trong bài học!
Đầu ra dự kiến:
Empty list
Single item: 42
Pair: hello and world
List starting with 1, length: 5
Alice is 25 years old
Negative: -10
Zero
Positive: 99Tự làm thử
import 'classifier.dart';
void main() {
// TODO: Dùng hàm (function) classify để phân loại từng giá trị
// và in ra kết quả
// Thử với một danh sách rỗng
print(classify([]));
// TODO: Thử với danh sách có một phần tử: [42]
// TODO: Thử với danh sách có hai phần tử: ['hello', 'world']
// TODO: Thử với danh sách dài hơn: [1, 2, 3, 4, 5]
// TODO: Thử với một map: {'name': 'Alice', 'age': 25}
// TODO: Thử với số nguyên -10
// TODO: Thử với số nguyên 0
// TODO: Thử với số nguyên 99
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiThư viện và câu lệnh importGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTừ khóa thisPhương thứcBiến thể hiệnKiến thức cơ bản về hàm khởi tạoÔn tập: Máy tính đơn giản4An toàn với giá trị null
Giới thiệu về an toàn với giá trị nullCó thể null và không thể nullToán tử ? và !Từ khóa late và an toàn với giá trị nullToán tử xử lý nullAn toàn với giá trị null trong lớpÔn tập: hệ thống hồ sơ người dùng7Lớp trừu tượng và interface
Lớp trừu tượngPhương thức trừu tượngInterface trong DartInterface ngầm địnhTriển khai và kế thừaNhiều interfaceÔn tập: Máy tính hình10Bộ sưu tập và kiểu tổng quát
Tổng quan về List, Set và MapBộ sưu tập an toàn về kiểuLớp tổng quátPhương thức tổng quátRàng buộc kiểu tổng quátIterable và IteratorÔn tập: Lưu trữ tổng quát13Khái niệm OOP nâng cao
Composition và kế thừaPhương thức mở rộngLớp có thể gọiLớp sealed (Dart 3)Records (Dart 3)Mẫu và đối sánh (3.0)Enum có phương thức2Hàm khởi tạo trong Dart
Hàm khởi tạo mặc địnhHàm khởi tạo có tênDanh sách khởi tạoHàm khởi tạo hằng sốHàm khởi tạo nhà máyHàm khởi tạo chuyển hướngÔn tập: Trình tạo hình dạng5Đóng gói
Thành viên công khai và riêng tưQuy ước tiền tố _Tính riêng tư ở cấp thư việnTìm hiểu sâu về getter và setterChe giấu thông tinÔn tập: hồ sơ học sinh8Mixin
Giới thiệu về MixinTạo MixinSử dụng nhiều MixinTừ khóa on trong MixinMixin và kế thừaMixin và giao diệnÔn tập: hệ thống động vật3Thuộc tính của lớp
Thành viên instance và thành viên tĩnhTrường final và constBiến latePhương thức và trường tĩnhGetter và setterÔn tập: trình quản lý tài khoản ngân hàng6Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChú thích @overrideTừ khóa lớp finalHàm khởi tạo và kế thừaÔn tập: phân cấp nhân viên9Đa hình
Khái niệm cơ bản về đa hìnhĐa hình qua giao diệnKiểm tra kiểu lúc chạyToán tử is và asTừ khóa hiệp biếnÔn tập: Bộ xử lý thanh toánTự luyện tập: Trình biên dịch Dart online