Lập trình · Ngôn ngữ lập trình
Học Dart cơ bản cho người mới bắt đầu
Trả lời nhanh
Dart là ngôn ngữ hướng đối tượng, kiểu tĩnh do Google phát triển, nổi tiếng nhất là ngôn ngữ của framework ứng dụng Flutter. Dart có sound null safety, biên dịch ra mã native cũng như JavaScript hoặc WebAssembly, và hỗ trợ hot reload nhanh khi phát triển. Trang này hướng dẫn cài đặt, kiểu dữ liệu, null safety, cấu trúc điều khiển, hàm, collection, lớp, mã bất đồng bộ và xử lý lỗi.
Dart là gì và dùng để làm gì
Dart là ngôn ngữ lập trình tối ưu cho phía client do Google phát triển. Dart có kiểu tĩnh kèm suy luận kiểu, có sound null safety, và biên dịch cả sang mã máy native (cho di động, desktop và máy chủ) lẫn JavaScript hoặc WebAssembly (cho web). Khi phát triển, Dart chạy trên máy ảo có hot reload, nên thay đổi hiện ra trong ứng dụng đang chạy chỉ sau vài giây.
Hầu hết mọi người học Dart để xây dựng ứng dụng bằng Flutter, bộ công cụ UI của Google cho Android, iOS, web, Windows, macOS và Linux từ một mã nguồn duy nhất. Dart cũng được dùng cho công cụ dòng lệnh và dịch vụ backend.
Cài đặt Dart và chạy Hello, world
Cài Dart SDK từ dart.dev (hoặc cài Flutter, bộ này đã kèm sẵn Dart). Mọi chương trình Dart đều bắt đầu từ hàm main ở cấp cao nhất.
// hello.dart
void main() {
print('Hello, world!');
}dart run hello.dart
# Hello, world!
dart compile exe hello.dart # builds a native executable
dart create my_app # creates a new console projectBạn cũng có thể chạy thử mọi ví dụ trong trang này trên DartPad, trình soạn thảo trên trình duyệt tại dartpad.dev.
Biến và các kiểu dữ liệu cơ bản
Dùng var để trình biên dịch tự suy ra kiểu, final cho biến chỉ gán một lần, và const cho hằng số xác định lúc biên dịch. Bạn luôn có thể ghi kiểu tường minh thay vào đó.
void main() {
var name = 'Dart'; // inferred as String
int year = 2011; // explicit type
final now = DateTime.now(); // set once, at run time
const pi = 3.14159; // compile-time constant
double ratio = 2; // int literal becomes 2.0
bool ok = year > 2000;
print('$name since $year, pi=${pi.toStringAsFixed(2)}, ok=$ok, ratio=$ratio');
// Dart since 2011, pi=3.14, ok=true, ratio=2.0
print(now.year > 2000); // true
}| Kiểu | Ví dụ | Ghi chú |
|---|---|---|
int | 42 | số nguyên; 64 bit trên các nền tảng native |
double | 3.14 | số thực dấu phẩy động 64 bit |
num | 7 or 7.5 | kiểu cha của int và double |
bool | true | điều kiện chỉ chấp nhận true và false |
String | 'hi' | UTF-16; hỗ trợ nội suy $x và ${expr} |
dynamic | bất kỳ giá trị nào | tắt kiểm tra tĩnh; nên tránh trong hầu hết mã |
Trên web, giá trị int được biểu diễn như số JavaScript, nên các số nguyên rất lớn có thể mất độ chính xác ở đó.
Sound null safety
Từ Dart 3, toàn bộ mã Dart dùng sound null safety. Biến kiểu String không bao giờ là null; để cho phép null, hãy viết String?. Trình biên dịch kiểm tra mọi chỗ dùng, nên lỗi null được phát hiện trước khi chương trình chạy.
int lengthOf(String? s) {
// return s.length; // compile error: s might be null
if (s == null) return 0;
return s.length; // promoted to String after the check
}
void main() {
String? nickname;
print(nickname?.length); // null (null-aware access)
print(nickname ?? 'guest'); // guest (default if null)
nickname ??= 'dee'; // assign only if null
print(lengthOf(nickname)); // 3
late String config; // initialized later, checked at run time
config = 'loaded';
print(config); // loaded
}Cấu trúc điều khiển
Dart có if, for, while và do-while quen thuộc, cùng vòng lặp for-in trên mọi iterable. Từ Dart 3, switch hỗ trợ so khớp mẫu (pattern matching) và có thể dùng như một biểu thức.
void main() {
var scores = [72, 95, 48];
for (var s in scores) {
if (s >= 90) {
print('$s excellent');
} else if (s >= 50) {
print('$s pass');
} else {
print('$s fail');
}
}
for (var i = 0; i < 3; i++) {
print('i = $i');
}
var day = 6;
var kind = switch (day) {
6 || 7 => 'weekend',
>= 1 && <= 5 => 'weekday',
_ => 'invalid',
};
print(kind); // weekend
}Hàm
Hàm là đối tượng hạng nhất. Tham số có thể là vị trí, vị trí tùy chọn trong [], hoặc có tên trong {}. Tham số có tên là tùy chọn trừ khi đánh dấu required. Cú pháp mũi tên => là cách viết tắt cho hàm trả về một biểu thức.
int add(int a, int b) => a + b;
String greet(String name, {String greeting = 'Hello', required bool loud}) {
var text = '$greeting, $name';
return loud ? text.toUpperCase() : text;
}
String label(String text, [int? width]) =>
width == null ? text : text.padRight(width, '.');
void main() {
print(add(2, 3)); // 5
print(greet('Ana', loud: false)); // Hello, Ana
print(greet('Ana', greeting: 'Hi', loud: true)); // HI, ANA
print(label('id', 5)); // id...
var twice = (int x) => x * 2; // anonymous function
print([1, 2, 3].map(twice).toList()); // [2, 4, 6]
}Collection: List, Set, Map và record
Các collection cốt lõi là List (có thứ tự), Set (phần tử duy nhất) và Map (cặp khóa-giá trị). Literal của collection hỗ trợ if, for và toán tử trải .... Record, thêm vào ở Dart 3, gom nhiều giá trị mà không cần khai báo lớp.
void main() {
var nums = [3, 1, 2]; // List<int>
nums.add(4);
nums.sort();
print(nums); // [1, 2, 3, 4]
var tags = {'dart', 'flutter', 'dart'};
print(tags.length); // 2
var ages = {'Ann': 31, 'Bo': 25}; // Map<String, int>
ages['Cy'] = 40;
print(ages['Bo']); // 25
var showAll = false;
var menu = ['Home', if (showAll) 'Admin', for (var n in nums) 'Item $n'];
print(menu); // [Home, Item 1, Item 2, Item 3, Item 4]
(String, int) pair = ('Ann', 31); // a record
var (who, age) = pair; // destructuring
print('$who is $age'); // Ann is 31
}Lớp và async/await
Dart hướng đối tượng: mọi giá trị đều là đối tượng. Lớp hỗ trợ constructor với tham số khởi tạo (this.x), constructor có tên, getter, mixin và interface. Mã bất đồng bộ dùng Future và Stream với async và await, giúp ứng dụng Flutter luôn phản hồi khi chờ tệp hoặc mạng.
class Point {
final double x, y;
const Point(this.x, this.y);
Point.origin() : x = 0, y = 0; // named constructor
double get sum => x + y; // getter
@override
String toString() => 'Point($x, $y)';
}
Future<String> fetchUser() async {
await Future.delayed(Duration(milliseconds: 100));
return 'ana';
}
Future<void> main() async {
print(Point(1, 2).sum); // 3.0
print(Point.origin()); // Point(0.0, 0.0)
var user = await fetchUser();
print('user: $user'); // user: ana
}Xử lý lỗi
Ném ngoại lệ bằng throw và xử lý bằng try, on, catch và finally. Dùng on SomeType để bắt một kiểu cụ thể. Dart phân biệt Exception (vấn đề dự kiến mà chương trình có thể xử lý) với Error (lỗi lập trình, như assertion thất bại hoặc lỗi vượt phạm vi) mà thông thường bạn không nên bắt.
int parseAge(String s) {
var n = int.tryParse(s); // null instead of throwing
if (n == null || n < 0) {
throw FormatException('Not a valid age: $s');
}
return n;
}
void main() {
for (var input in ['42', 'abc']) {
try {
print(parseAge(input));
} on FormatException catch (e) {
print('Error: ${e.message}');
} finally {
print('checked $input');
}
}
}
// 42 / checked 42 / Error: Not a valid age: abc / checked abcMột chương trình hoàn chỉnh nhỏ: tổng tiền giỏ hàng
Chương trình này mô hình hóa sản phẩm bằng một lớp, lưu giỏ hàng trong một map và in hóa đơn. Nó kết hợp lớp, map, định dạng chuỗi và các phương thức của collection.
class Product {
final String name;
final double price;
const Product(this.name, this.price);
}
void main() {
const apple = Product('Apple', 0.5);
const bread = Product('Bread', 2.25);
final cart = <Product, int>{apple: 6, bread: 2};
var total = 0.0;
cart.forEach((product, qty) {
final line = product.price * qty;
total += line;
print('${product.name.padRight(6)} x$qty ${line.toStringAsFixed(2)}');
});
final count = cart.values.reduce((a, b) => a + b);
print('$count items, total ${total.toStringAsFixed(2)}');
}
// Apple x6 3.00
// Bread x2 4.50
// 8 items, total 7.50Học tiếp ở đâu
- Language tour và các hướng dẫn về Dart tại dart.dev.
- Effective Dart, hướng dẫn chính thức về phong cách và thiết kế.
- Tài liệu Flutter tại flutter.dev nếu bạn muốn xây dựng ứng dụng.
- pub.dev, kho gói của Dart và Flutter.
Câu hỏi thường gặp
Dart chỉ dùng cho Flutter thôi à?
Không. Dart là ngôn ngữ đa dụng và có thể dùng để viết công cụ dòng lệnh, máy chủ và ứng dụng web. Flutter chỉ đơn giản là lý do phổ biến nhất để học Dart.
Dart là ngôn ngữ biên dịch hay thông dịch?
Có cả hai chế độ. Khi phát triển, Dart chạy trên VM với biên dịch JIT (just-in-time) và hot reload; khi phát hành, nó được biên dịch AOT (ahead-of-time) ra mã máy native, hoặc ra JavaScript hay WebAssembly cho web.
final và const trong Dart khác nhau thế nào?
Biến final chỉ gán một lần, có thể ở lúc chạy. Giá trị const phải biết ngay lúc biên dịch và bất biến hoàn toàn, nhờ đó Flutter có thể tái sử dụng các widget hằng.
Dart có giống Java hay JavaScript không?
Cú pháp kiểu C và các lớp của Dart quen thuộc với lập trình viên Java, C# và JavaScript. Khác JavaScript, Dart có kiểu tĩnh và sound null safety.
Toán tử ?? trong Dart làm gì?
a ?? b trả về a nếu a không null, ngược lại trả về b. Toán tử liên quan a ??= b chỉ gán b cho a khi a là null.