Bạn có chắc chắn muốn xóa bài viết này không ?
Bạn có chắc chắn muốn xóa bình luận này không ?
Những điểm đánh dấu khi tìm hiểu về Dart
Những điểm đánh dấu khi tìm hiểu về Dart
Mình cùng với ông anh chơi chung nó cùng chạy đua một thử thách xem ai học Flutter nhanh nhất. Sau đây là thành quả sau ba đêm cuối tuần cày Dart lang là ngôn ngữ được sử dụng trong Flutter. Để đọc hiểu bài này, bạn cần phải có kinh nghiệm code một hoặc vài ngôn ngữ lập trình trước đó. Bài viết không phải bài hướng dẫn mà chỉ là phần note lại các điểm được mình cho là quan trọng sau khi đọc docs của Dart. Những phần không quan trọng mặc định bỏ qua.
Trong Dart mọi thứ đều là object
Trong Dart mọi thứ đều là object. Đã là Object thì luôn phải là instance của một class nào đó. Chính vì tất cả đều là object nên dù là số, chữ hay bất kể loại kiểu dữ liệu nào thì giá trị mặc định của nó đều là null
. Nhờ vậy, mọi biến số trong Dart đều là reference type
. Cũng chính thế mà Dart có một loại biến dynamic
chấp nhận mọi kiểu dữ liệu.
Non-dynamic data type
main () {
var x = 1;
x = 1.5; // Error: A value of type 'double' can't be assigned to a variable of type 'int'
}
Dynamic data type
main () {
dynamic x = 1;
x = 1.5;
}
Toán tử Null-aware
Vì giá trị mặc định của mọi thứ trong Dart đều là null. Điều này đi ngược lại xu thế phát triển của xã hội. Chính vì vậy mà Dart có một loạt toán tử Null-aware để đảm bảo null safe trong quá trình thực thi code.
Ví dụ về Null-aware
void main() {
print(null ?? 'Trả về chính nó nếu khác null hoặc trả về dòng này');
var x = null;
x ??= 'Syntax sugar của `x = x ?? "Viết gì vào đây bây giờ"`';
print(x);
var isNull = null;
print(isNull?.foo()); // Nếu null thì không thực hiện foo() nữa mà trả về `null`
}
Một trong những lưu ý có liên quan đó là mọi hàm trong Dart đều trả về dữ liệu. Mặc định trả về của một hàm cũng là null
.
Có năm cách để đánh dấu khai báo một biến/hằng số trong Dart
- Cách đầu tiên là đặt kiểu dữ liệu trước tên biến. Biến sẽ chỉ được khai báo một lần và tất cả mọi lần thay đổi dữ liệu biến đều phải giữ nguyên kiểu dữ liệu cũ.
- Sử dụng
var
giúp cho biến dù được khai báo một lần và không thể thay đổi kiểu dữ liệu. Tuy nhiên sau lần nhận dữ liệu đầu tiên, biến mới được xác định kiểu dữ liệu của bản thân. - Sử dụng
dynamic
giúp cho biến dù được khai báo một lần nhưng muốn thay đổi dữ liệu và kiểu dữ liệu bao nhiêu lần cũng được. -
final
vàconst
là hai từ khóa dễ nhầm cần được nói riêng.
Một biến được khai báo là final
sẽ trở thành hằng số chỉ có thể được truyền dữ liệu một lần. Tuy nhiên dữ liệu vẫn có thể tự thay đổi các giá trị thuộc tính bên trong nó.
Ví dụ về final
class A {
var a = 'dummy';
}
main() {
final a = A();
assert(a.a == 'dummy');
a.a = 'new';
assert(a.a == 'new');
a = A(); // Error: 'a', a final variable, can only be set once
}
Một biến được khai báo là const
sẽ trở thành hằng số được build thành các literal
tại thời điểm compile time
. Điều này nghĩa là toàn bộ dữ liệu được truyền vào đều bị đóng băng và không thể thay đổi
. Và vì được build vào thời điểm compile time
dẫn đến phần tử của object thì không thể là const
được. Một biến muốn được khai báo là const
thì buộc phải static
hoặc là top-level variable
.
Ngoài ra, const
cũng có thể được dùng cho việc khai báo cho khối dữ liệu truyền vào. Lí do thì nó rất là buồn cười, để tôi chỉ các bạn thấy.
Ví dụ về const
main() {
var a = const []; // (1) a có thể được đổi thành giá trị khác ngoài một list rỗng ([])
final b = const []; // (2) b chính là const chứ còn gì nữa
const c = const []; // (3) c được khuyến cáo là viết thừa
}
Trường hợp (2) chính là lí do. Vì một phần tử của object không thể là const
vì lí do tại thời điểm compile time
thì nó chưa tồn tại. Vậy cách để thực hiện việc này là tạo ra một khối dữ liệu const
được build tại thời điểm compile time
là list rỗng ([]). Đến lúc xuất hiện object thì ta đặt phần tử mong muốn thành final, truyền cho nó khối dữ liệu ([]) và a lê hấp nó đã biến thành một phần tử const
.
Dart hỗ trợ UTF-32
Vì mặc định một kí tự Unicode được biểu diễn như regex sau: \\u[0-9a-f]{4}
ví dụ \u09af
. Điều này cho thấy là một kí tự chỉ biểu diễn được tối đa là 4 kí tự hex có tổng là 16 bits. Vậy để biểu diễn được UTF-32, Dart đưa ra một cú pháp được gọi là Runes có các biểu diễn như regex sau: \\u\{[0-9a-f]{1, 8}\}
ví dụ \u09af
, \u09
, \u09affa90
Dart hỗ trợ đa kế thừa
Về mặt cú pháp thì Dart vẫn chỉ có một kế thừa duy nhất, tuy nhiên Dart lại hỗ trợ kĩ thuật mixins thông qua từ khóa with. Việc này dẫn đến diamon problem
là việc khi kế thừa lại có ít nhất hai supper class có ít nhất một method cùng tên và cùng danh sách tham số truyền vào. Điều này gây ra là ở phía sub-class khi gọi đến method đó thì không biết chọn cái nào. Với Dart, câu trả lời là của supper class cuối cùng được khai báo. Vậy điểm lưu ý là thứ tự khai báo rất quan trọng trong Dart
.
Dart không có accept modifier
Trong Dart thì cùng một file.Dart
với nhau thì mọi thứ là public. Còn với những tài nguyên thuộc về file.Dart
khác. Tên biến có bắt đầu bởi kí tự _
thì được coi là private ở mức độ packages/files/libraries.
Vậy nếu không có private, làm sao triển khai được singleton? Dart lại sinh ra một keyword gọi là factory
. Với factory ta sẽ triển khai được một singleton như sau:
Giới thiệu về singleton trong Dart
class Singleton {
static final Singleton _singleton = new Singleton._internal();
factory Singleton() {
return _singleton;
}
Singleton._internal();
}
main() {
var s1 = new Singleton();
var s2 = new Singleton();
assert(identical(s1, s2));
assert(s1 == s2);
}
Tham số dạng positional và named trong Dart
Dart đưa ra hai khái niệm là positional
và named
tham số. Hai khái niệm này khác nhau ở điểm. positional
cho phép ta đặt giá trị mặc định hoặc không (mặc định là null) cho tham số truyền vào. Từ đó, ta có thể thêm bớt số lượng tham số trong lời gọi hàm. Ràng buộc của positional
là vị trí khai báo phải nằm cuối cùng trong phần khai báo. Danh sách positional
trong lời gọi hàm không được thay đổi thứ tự.
Ví dụ về positional
getNumber(String one, String two, [int three, String four]) {
return '$one, $two, $three, $four';
}
main() {
assert(getNumber('1', '2') == '1, 2, null, null');
assert(getNumber('1', '2', 3) == '1, 2, 3, null');
assert(getNumber('1', '2', 3, '4') == '1, 2, 3, 4');
}
named
thì linh hoạt hơn khi chấp nhận không theo thứ tự khi gọi hàm miễn là thỏa mãn việc tên tham số được chỉ rõ. Lưu ý là không thể có cả positional lẫn named trong cùng một method
.
Ví dụ về named
getNumber(String one, String two, {int three, String four}) {
return '$one, $two, $three, $four';
}
main() {
assert(getNumber('1', '2') == '1, 2, null, null');
assert(getNumber('1', '2', three: 3) == '1, 2, 3, null');
assert(getNumber('1', '2', four: '4') == '1, 2, null, 4');
}
Đại khái note lại là vậy






