Records (Dart 3)
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 86 trên 110.
Dart 3 giới thiệu records, một cách gọn nhẹ để nhóm nhiều giá trị lại với nhau mà không cần tạo cả một lớp. Records không thể thay đổi, có sẵn phép so sánh bằng và rất phù hợp để trả về nhiều giá trị từ một hàm hoặc tạm thời nhóm các dữ liệu liên quan.
Tạo một bản ghi bằng cách đặt các giá trị trong dấu ngoặc đơn:
void main() {
// Một bản ghi (record) đơn giản với hai giá trị (value)
var point = (10, 20);
print(point.$1); // 10: truy cập phần tử (element) đầu tiên
print(point.$2); // 20: truy cập phần tử thứ hai
// Các bản ghi có trường được đặt tên
var person = (name: 'Alice', age: 30);
print(person.name); // Alice
print(person.age); // 30
}Truy cập các trường theo vị trí bằng $1, $2, v.v., còn các trường có tên thì dùng trực tiếp tên của chúng. Bạn có thể kết hợp cả hai kiểu trong một bản ghi.
Bản ghi rất hữu ích khi hàm trả về nhiều giá trị, bạn không cần tạo lớp chỉ để trả về hai phần dữ liệu:
(int, int) divideWithRemainder(int a, int b) {
return (a ~/ b, a % b);
}
(String name, int age) getUser() {
return ('Bob', 25);
}
void main() {
var (quotient, remainder) = divideWithRemainder(17, 5);
print('$quotient remainder $remainder'); // 3 remainder 2
var (name, age) = getUser();
print('$name is $age'); // Bob là 25
}Các record tự động hỗ trợ phép so sánh bằng dựa trên giá trị, giúp bạn so sánh thuận tiện mà không cần tự triển khai ==. Dùng record khi bạn cần nhóm dữ liệu đơn giản, bất biến; dùng lớp khi bạn cần phương thức, khả năng thay đổi hoặc hành vi phức tạp hơn.
Thử thách
DễHãy cùng xây dựng một hệ tọa độ bằng các record! Bạn sẽ tạo các hàm hoạt động với điểm 2D được biểu diễn dưới dạng record, qua đó thấy được record giúp trả về và làm việc với nhiều giá trị liên quan dễ dàng như thế nào mà không cần tạo lớp đầy đủ.
Bạn sẽ sắp xếp code vào hai tệp:
geometry.dart: Tạo các hàm dùng record để làm việc với dữ liệu tọa độ:- Một hàm
createPoint(int x, int y)trả về một record có các trường được đặt tên làxvày. Kiểu trả về cần là({int x, int y}) - Một hàm
midpoint(({int x, int y}) p1, ({int x, int y}) p2)tính và trả về trung điểm giữa hai điểm dưới dạng record có các trường được đặt tên. Dùng phép chia nguyên (~/) để tính - Một hàm
distance(({int x, int y}) p1, ({int x, int y}) p2)trả về một record có các trường theo vị trí: khoảng cách ngang (độ chênh lệch theo x) và khoảng cách dọc (độ chênh lệch theo y). Kiểu trả về cần là(int, int). Tính bằngp2.x - p1.xvàp2.y - p1.y
- Một hàm
main.dart: Nhập tệp hình học của bạn và minh họa cách dùng record:- Tạo hai điểm bằng
createPoint: điểm A tại(2, 4)và điểm B tại(10, 8) - In
Point A: ([x], [y])bằng các trường được đặt tên - In
Point B: ([x], [y])bằng các trường được đặt tên - Tính trung điểm và in
Midpoint: ([x], [y]) - Tính khoảng cách và dùng phép phân rã để lấy các giá trị vào hai biến
dxvàdy, sau đó inDistance: dx=[dx], dy=[dy]
- Tạo hai điểm bằng
Hãy chú ý cách record giúp bạn trả về nhiều giá trị một cách gọn gàng: dùng trường được đặt tên để rõ nghĩa khi cần, còn trường theo vị trí khi ngữ cảnh đã rõ!
Đầu ra dự kiến:
Point A: (2, 4)
Point B: (10, 8)
Midpoint: (6, 6)
Distance: dx=8, dy=4Tự làm thử
import 'geometry.dart';
void main() {
// TODO: Tạo điểm A tại (2, 4) bằng createPoint
// TODO: Tạo điểm B tại (10, 8) bằng createPoint
// TODO: In ra điểm A bằng các trường có tên: Point A: ([x], [y])
// TODO: In ra điểm B bằng các trường có tên: Point B: ([x], [y])
// TODO: Tính trung điểm rồi in ra: Midpoint: ([x], [y])
// TODO: Tính khoảng cách và dùng phép phân rã để lấy dx và dy
// Sau đó in ra: Distance: dx=[dx], dy=[dy]
}
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