Không nullable (theo mặc định)
Thử nghiệm không nullable (theo mặc định) hiện có thể được tìm thấy tại nullsquil.dartpad.dev .
Hãy nhớ rằng bạn có thể đọc thông số kỹ thuật đầy đủ ở đây và lộ trình đầy đủ ở đây .
Không mặc định có nghĩa là gì?
void main() {
String word;
print(word); // illegal
word = 'Hello, ';
print(word); // legal
}
Như bạn có thể thấy ở trên, một biến không thể rỗng theo mặc định có nghĩa là mọi biến được khai báo bình thường đều không thể null
. Do đó, bất kỳ hoạt động truy cập vào biến trước khi nó được chỉ định là bất hợp pháp.
Ngoài ra, việc gán null
cho một biến không có giá trị cũng không được phép:
void main() {
String word;
word = null; // forbidden
world = 'World!'; // allowed
}
Điều này giúp tôi như thế nào?
Nếu một biến là không thể rỗng , bạn có thể chắc chắn rằng nó không bao giờ null
. Do đó, bạn không bao giờ cần phải kiểm tra trước.
int number = 4;
void main() {
if (number == null) return; // redundant
int sum = number + 2; // allowed because number is also non-nullable
}
Nhớ lại
Các trường sơ thẩm trong các lớp phải được khởi tạo nếu chúng không thể rỗng:
class Foo {
String word; // forbidden
String sentence = 'Hello, World!'; // allowed
}
Xem late
bên dưới để sửa đổi hành vi này.
Các loại không thể ( ?
)
Bạn có thể sử dụng các loại nullable bằng cách nối thêm một dấu hỏi ?
vào một loại biến:
class Foo {
String word; // forbidden
String? sentence; // allowed
}
Một biến nullable không cần phải được khởi tạo trước khi nó có thể được sử dụng. Nó được khởi tạo như null
mặc định:
void main() {
String? word;
print(word); // prints null
}
!
Áp dụng !
cho bất kỳ biến nào e
sẽ gây ra lỗi thời gian chạy nếu e
là null và nếu không thì chuyển đổi nó thành một giá trị không thể rỗngv
.
void main() {
int? e = 5;
int v = e!; // v is non-nullable; would throw an error if e were null
String? word;
print(word!); // throws runtime error if word is null
print(null!); // throws runtime error
}
late
Từ khóa late
có thể được sử dụng để đánh dấu các biến sẽ được khởi tạo sau , tức là không phải khi chúng được khai báo mà là khi chúng được truy cập. Điều này cũng có nghĩa là chúng ta có thể có các trường đối tượng không thể rỗng được khởi tạo sau:
class ExampleState extends State {
late String word; // non-nullable
@override
void initState() {
super.initState();
// print(word) here would throw a runtime error
word = 'Hello';
}
}
Truy cập word
trước khi nó được khởi tạo sẽ gây ra lỗi thời gian chạy.
late final
Biến cuối cùng bây giờ cũng có thể được đánh dấu muộn:
late final int x = heavyComputation();
Ở đây heavyComputation
sẽ chỉ được gọi một lần x
được truy cập. Ngoài ra, bạn cũng có thể khai báo late final
không có bộ khởi tạo, giống như chỉ có một late
biến, nhưng nó chỉ có thể được gán một lần.
late final int x;
// w/e
x = 5; // allowed
x = 6; // forbidden
Lưu ý rằng tất cả các biến cấp cao nhất hoặc tĩnh với trình khởi tạo bây giờ sẽ được đánh giá late
, bất kể chúng là gì final
.
required
Trước đây là một chú thích ( @required
), bây giờ được tích hợp làm công cụ sửa đổi. Nó cho phép đánh dấu bất kỳ tham số được đặt tên nào (cho các hàm hoặc các lớp) là required
, làm cho chúng không thể rỗng:
void allowed({required String word}) => null;
Điều này cũng có nghĩa là nếu một tham số không thể rỗng , thì nó cần được đánh dấu là required
hoặc có giá trị mặc định:
void allowed({String word = 'World'}) => null;
void forbidden({int x}) // compile-time error because x can be null (unassigned)
=>
null;
Bất kỳ tham số được đặt tên nào khác phải là nullable :
void baz({int? x}) => null;
?[]
?[]
Toán tử nhận biết null đã được thêm cho toán tử chỉ mục []
:
void main() {
List<int>? list = [1, 2, 3];
int? x = list?[0]; // 1
}
Xem thêm bài viết này về quyết định cú pháp .
?..
Toán tử ghép tầng bây giờ cũng có toán tử nhận biết null mới : ?..
.
Nó làm cho các hoạt động theo tầng sau chỉ được thực hiện nếu người nhận không phải là null . Do đó, ?..
phải là toán tử phân tầng đầu tiên trong chuỗi phân tầng:
void main() {
Path? path;
// Will not do anything if path is null.
path
?..moveTo(3, 4)
..lineTo(4, 3);
// This is a noop.
(null as List)
?..add(4)
..add(2)
..add(0);
}
Never
Để tránh nhầm lẫn: đây không phải là điều mà các nhà phát triển phải lo lắng. Tôi muốn đề cập đến nó vì lợi ích của sự hoàn chỉnh.
Never
sẽ là một loại giống như trước đây Null
( khôngnull
) được xác định trong dart:core
. Cả hai lớp này không thể được mở rộng, thực hiện hoặc trộn lẫn, vì vậy chúng không có ý định sử dụng.
Về cơ bản, Never
có nghĩa là không có loại nào được cho phép và Never
bản thân nó không thể được khởi tạo.
Không có gì nhưng Never
trong một List<Never>
thỏa mãn loại ràng buộc chung của danh sách, có nghĩa là nó phải trống . List<Null>
tuy nhiên, có thể chứa null
:
// Only valid state: []
final neverList = <Never>[
// Any value but Never here will be an error.
5, // error
null, // error
Never, // not a value (compile-time error)
];
// Can contain null: [null]
final nullList = <Null>[
// Any value but Null will be an error.
5, // error
null, // allowed
Never, // not a value (compile-time error)
Null, // not a value (compile-time error)
];
Ví dụ: trình biên dịch sẽ suy ra List<Never>
một khoảng trống const List<T>
.
Never
không được sử dụng bởi các lập trình viên theo như tôi nghĩ.
Never
có thể được sử dụng?