[Dart&Flutter][Bài2]Biến và kiểu dữ liệu trong Dart (P.1)

Xin chào anh em. Ở phần trước mình đã giới thiệu sơ qua về Dart và Flutter, cách Flutter hoạt động và biên dịch ngôn ngữ Dart. Hôm nay, mình sẽ giới thiệu sâu hơn về Dart, biến và kiểu dữ liệu của nó.

  1. Biến

Như tất cả các ngôn ngữ lập trình khác, biến là một trong số những phần cơ bản  mà tất cả lập trình viên cần nắm để có thể viết được một chương trình., và Dart hỗ trợ tự động đoán kiểu dữ liệu của biến đó là gì (kiểu tự suy - type inference). Một ví dụ cho việc khai báo một biến phổ biến trong Dart:

var age = 39;
var name = 'Example';

Ta có thể thấy, age là số nguyên và name  là một chuỗi. Như Kotlin, Dart có thể nhận ra dạng biến này bằng cách nhìn vào giá trị chúng ta truyền vào. Nói cách khác, trình biên dịch của Dart đủ thông minh để tự mình nhận ra loại biến chính xác. Và tất nhiên, bạn vẫn có thể khai báo tường minh cho biến trong Dart.

int age = 39;
String name = 'Example';

Ngoài ra, còn một kiểu khai báo nữa nhưng ít được dùng đến.

dynamic age = 18;
dynamic name = 'Example';

dynamic như tên gọi của nói, là một kiểu biến động, có thể được dùng với bất kì loại biến nào, bất kì giá trị nào cũng có thể được gán với nó. Kiểu biến dynamic được tính toán trong thời gian chạy chương trình(runtime), do đó để sử dụng đúng cách, bạn cần phải làm với check và cast. Theo hướng dẫn của Dart, bạn nên:

  • Sử dụng var để khai báo biến.
  • Với biến khó đoán kiểu dữ liệu khi nhìn, khai báo biến kiểu tường minh (String, int,.....).
  • Hạn chế sử dụng Object hoặc dynamic, chỉ sử dụng khi thực sự cần thiết.

Trên thực tế, dynamic không thực sự là 1 kiểu: Đó là một cách để loại bỏ phân tích tĩnh và cho trình biên dịch biết bạn đang làm gì. Trường họp duy nhất chúng ta thực sự sử dụng đến nó là trong Flutter liên quan đến mã hóa và giải mã JSON.

1.1. Khai báo/Khởi tạo

Theo hướng dẫn của Dart,  chúng ta sẽ sử dụng khai báo biến với var hơn là kiểu tường minh. Lí do là vì khai báo với var giúp code ngắn gọn hơn và tăng khả năng đọc hiểu code. Ví dụ:

// các kiểu dữ liệu lồng vào nhau, khó đọc, rối code

List<List<Toppings>> pizza = List<List<Toppings>>();\

for(List<Toppings> topping in pizza) {
	doSomething(topping);
}
// code trông ngắn gọn, dễ hiểu hơn

var pizza = List<List<Toppings>>();

for(var topping in pizza) {
	doSomething(topping);
}

Các trường hợp nên viết nên khai báo biến theo kiểu tường mình:

  • Khi bạn không muốn khởi tạo một biến ngày lập tức, bạn sử dụng late, thì cần khai báo tường minh (mình sẽ giải thích late trong những bài sau)
 late List<String> names;
	if (iWantFriends())
	 	names = friends.getNames(); 
	else 
		names = haters.getNames();

 Nếu sử dụng var thay vì List<String>, kiểu được suy ra sẽ là null, đó không phải điểu mong muốn. Và biến đó sẽ mất tính an toàn và khả năng đọc. (chúng ta sẽ bàn về null safety ở những bài sau)

  • Khi chúng ta  nói về kiểu biến tự suy, có nghĩa là ở lần khai báo sau sẽ không được xem xét mà nó sẽ tự suy luôn. Nếu những kiểu đó rõ ràng thì hãy tự suy còn nếu không được như mong muốn, thì bạn thêm kiểu chỉ định cho nó.
main() {
  var number = 3;
  print(number);

  number = 3.2;
  print(number);
}

 Ví dụ trên mình có khai báo number bằng từ khóa var. Nhưng mình muốn nó nhận cả kiểu int double. Khi đó, output sẽ bị lỗi.Vì ban đầu khi khởi tạo, mình đã gán cho nó số nguyên thì trình biên dịch sẽ suy number là kiểu int. Cho nên sau đó gán cho nó kiểu số thực, nó báo lỗi ngay. Trong trường hợp này, chúng ta cần khai báo tường minh cho number với kiểu dữ liệu là num. (num là kiểu dữ liệu bao gồm int double.)

1.2. final

Một biến được khai báo final có thể được đặt chỉ một lần duy nhất và nếu bạn cố thay đổi dữ liệu trong nó, bạn sẽ gặp lỗi. Ví dụ, bạn sẽ không thể biên dịch thành công đoạn code dưới đây

final name = "Cuong ket";
name = "Cuong";

Hãy chú ý rằng final cũng có thể tự động suy ra kiểu dữ liệu của biến tương tự như var. Từ khóa này có thể hiểu như là "var hạn chế" vì  có thể tự động xác định kiểu dữ liệu nhưng không thể thay đổi dữ liệu sau khi khởi tạo.

Bạn cũng có thể khai báo final với kiểu chỉ định, nhưng không thực sự cần thiết

// không thực sự cần thiết
final String nickName = "Cường";

Hãy nhớ rằng, sử dụng final khi biết rằng, sau khi được chỉ định, giá trị sẽ không bao giờ thay đổi nữa. Nếu bạn biết giá trị có thể thay đổi trong tương lai, hãy dùng var và suy nghĩ cả đến việc sử dụng biến chỉ định.

void main() {
	final jsonFile = File('myfile.json').readAsString();
	checkSyntax(jsonFile);
	saveToDisk(jsonFile, 'file.json');
}

Với ví dụ trên, khi mà nội dung tệp myfile.json không thể chỉnh sửa, do đó nó sẽ không thay đổi và sử dụng final là hợp lí.

Nếu bạn sử dụng var thì mã vẫn được biên dịch nhưng nó sẽ không phải là lựa chọn tốt nhất. Nếu mã dài hơn và phức tạp hơn, bạn có thể vô tình thay đổi nội dung của jsonFile vì sẽ không có "sự bảo vệ" của final.

Tham khảo: Flutter Complete Reference