Tôi thấy câu trả lời của Lasse trên blog Chris Storms là một lời giải thích tuyệt vời.
Tôi hy vọng họ không phiền vì tôi sao chép nội dung.
Đây là một lời giải thích tốt về các trường cuối cùng, nhưng nó không thực sự giải thích các hàm tạo const. Không có gì trong các ví dụ này thực sự sử dụng rằng các hàm tạo là các hàm tạo const. Bất kỳ lớp nào cũng có thể có các trường cuối cùng, các hàm tạo const hoặc không.
Một trường trong Dart thực sự là một vị trí lưu trữ ẩn danh kết hợp với getter và setter được tạo tự động để đọc và cập nhật bộ nhớ, đồng thời nó cũng có thể được khởi tạo trong danh sách bộ khởi tạo của phương thức khởi tạo.
Trường cuối cùng cũng vậy, chỉ cần không có bộ cài đặt, vì vậy cách duy nhất để đặt giá trị của nó là trong danh sách bộ khởi tạo phương thức khởi tạo, và không có cách nào để thay đổi giá trị sau đó - do đó là "cuối cùng".
Điểm của các hàm tạo const là không khởi tạo các trường cuối cùng, bất kỳ hàm tạo nào cũng có thể làm điều đó. Vấn đề là tạo các giá trị hằng số thời gian biên dịch: Các đối tượng trong đó tất cả các giá trị trường đã biết tại thời điểm biên dịch mà không cần thực hiện bất kỳ câu lệnh nào.
Điều đó đặt ra một số hạn chế đối với lớp và hàm tạo. Một phương thức khởi tạo const không được có phần thân (không có câu lệnh nào được thực thi!) Và lớp của nó không được có bất kỳ trường nào không phải là trường cuối cùng (giá trị mà chúng ta "biết" tại thời điểm biên dịch không thể thay đổi sau này). Danh sách trình khởi tạo cũng phải chỉ khởi tạo các trường thành các hằng số thời gian biên dịch khác, do đó, các cạnh bên phải được giới hạn trong "các biểu thức hằng số thời gian biên dịch" [1]. Và nó phải được bắt đầu bằng "const" - nếu không bạn chỉ nhận được một hàm tạo bình thường đáp ứng các yêu cầu đó. Điều đó hoàn toàn ổn, nó không phải là một hàm tạo const.
Để sử dụng một hàm tạo const để thực sự tạo một đối tượng hằng số thời gian biên dịch, sau đó bạn thay thế "new" bằng "const" trong một biểu thức-"mới". Bạn vẫn có thể sử dụng "new" với một const-constructor, và nó sẽ vẫn tạo một đối tượng, nhưng nó sẽ chỉ là một đối tượng mới bình thường, không phải là một giá trị hằng thời gian biên dịch. Nghĩa là: Một hàm tạo const cũng có thể được sử dụng như một hàm tạo bình thường để tạo các đối tượng trong thời gian chạy, cũng như tạo các đối tượng hằng số thời gian biên dịch tại thời điểm biên dịch.
Vì vậy, như một ví dụ:
class Point {
static final Point ORIGIN = const Point(0, 0);
final int x;
final int y;
const Point(this.x, this.y);
Point.clone(Point other): x = other.x, y = other.y; //[2]
}
main() {
// Assign compile-time constant to p0.
Point p0 = Point.ORIGIN;
// Create new point using const constructor.
Point p1 = new Point(0, 0);
// Create new point using non-const constructor.
Point p2 = new Point.clone(p0);
// Assign (the same) compile-time constant to p3.
Point p3 = const Point(0, 0);
print(identical(p0, p1)); // false
print(identical(p0, p2)); // false
print(identical(p0, p3)); // true!
}
Hằng số thời gian biên dịch được chuẩn hóa. Điều đó có nghĩa là cho dù bạn viết "const Point (0,0)" bao nhiêu lần, bạn chỉ tạo một đối tượng. Điều đó có thể hữu ích - nhưng không nhiều như bạn tưởng, vì bạn chỉ có thể tạo một biến const để giữ giá trị và sử dụng biến thay thế.
Vậy, hằng số thời gian biên dịch có ích gì?
- Chúng hữu ích cho enums.
- Bạn có thể sử dụng các giá trị hằng số thời gian biên dịch trong các trường hợp chuyển đổi.
- Chúng được dùng làm chú thích.
Các hằng số thời gian biên dịch từng quan trọng hơn trước khi Dart chuyển sang khởi tạo biến một cách lười biếng. Trước đó, bạn chỉ có thể khai báo một biến toàn cục đã khởi tạo như "var x = foo;" nếu "foo" là hằng số thời gian biên dịch. Nếu không có yêu cầu đó, hầu hết các chương trình có thể được viết mà không cần sử dụng bất kỳ đối tượng const nào
Vì vậy, tóm tắt ngắn gọn: Các hàm tạo Const chỉ để tạo các giá trị hằng số thời gian biên dịch.
/ L
[1] Hay thực sự là: "Biểu thức hằng thời gian biên dịch tiềm năng" vì nó cũng có thể tham chiếu đến các tham số của hàm tạo. [2] Vì vậy, có, một lớp có thể có cả hàm tạo const và không phải const cùng một lúc.