Dart 2.7: Có gì mới?

HauTV
OneID Engineering
Published in
5 min readJan 1, 2020

Năm 2019 là 1 năm đầy bận rộn, thách thức đối với cộng đồng Dart nói chung và Flutter nói riêng, giữa bộn bề của tốc độ phát triển 1 ngôn ngữ lập trình mới mà đứng sau nó là gã khổng lồ Google, còn nhiều điều chưa hoàn hảo nhưng tin vui dành cho những ai đặt niềm tin vào Dart-Flutter đó là vị trí #1–532% trên bảng xếp hạng những ngôn ngữ tăng trưởng nhanh nhất dựa trên số contributor.

https://octoverse.github.com/#top-languages

Cuối 2019, Dart công bố bản release 2.7 cuối cùng trong năm với một số tính năng đáng mong chờ hứa hẹn một ngôn ngữ lập trình an toàn hơn, dễ dàng hơn.Vậy Dart 2.7 có gì?

Photo by Michael Thomsen on Medium

Extension methods

Ở phiên bản Dart 2.7, Dart bổ sung thêm tính năng rất hay và đáng được mong chờ: Extension methods. Extension method cho chép bạn thêm phương thức mở rộng vào bất kỳ kiểu, lớp nào mà không cần phải kế thừa để mở rộng nó.

Đối với lớp String, bạn không thể thay đổi nó bởi vì nó được định nghĩa trong thư viện dart:core, nhưng với extension methods bạn có thể mở rộng nó, ví dụ: với lớp String có các phương thức mặc định là .toString(), .trim(), .toLowerCase(), .split(),…Bạn muốn có thêm một số phương thức mới như .isEmail(), .toNumber(), .toDatetime()…thì Extension methods sẽ giúp bạn thực hiện việc đó.

Hãy cùng xem qua một ví dụ nhỏ dưới đây:

Mỗi khi bạn định nghĩa phần mở rộng cho một lớp, bạn có thể gọi phương thức mở rộng mà bạn đã định nghĩa trên lớp đó đơn giản như là cách gọi phương thức tĩnh.

Extension methods là phương thức tĩnh, điều đó có nghĩa là bạn không thể sử dụng chúng trên các giá trị có kiểu dynamic. Tuy nhiên, Extension methods có thể sử dụng tốt với kiểu dữ liệu suy diễn (type inference)

dynamic d = '2';
d.isEmail;
→ Runtime exception
var v = “abc”;
v.isEmail // Work!

Ở ví dụ trên, khi gọi extension method trên giá trị có kiểu dynamic trình dịch sẽ ném ra một ngoại lệ bởi vì extension methods là phương thức tĩnh và được gọi nhanh như các static function.

Bạn có thể đã quen với thuật ngữ Extension methods ở một số ngôn ngữ khác nhưng trên Dart, extension methods còn hỗ trợ mở rộng class với các phương thức đặc biệt như getters, setters như ở ví dụ trên và hỗ trợ cả operators. Dưới đây là một ví dụ shift operator:

Một số lập trình viên nhiều kinh nghiệm đã sử dụng extension methods cho một số ứng dụng thú vị, ví dụ như Marcelo Glasberg sử dụng extension methods tạo ra một package i18 vô cùng dễ sử dụng:

Text('Hello'.i18n) // Displays Hello in English, Hola in Spanish, etc.

Safe substring

Lớp String của Dart sử dụng bảng mã UTF-16, UTF-16 là lựa chọn phổ biến của nhiều ngôn ngữ lập trình, đặc biệt là các ngôn ngữ hỗ trợ cả thiết bị native và web.

Các chuỗi sử dụng bản mã UTF-16 thường hoạt động tốt tuy nhiên khi thao tác chuỗi và đặc biệt là chuỗi do người dùng nhập vào có thể gặp phải một số sự khác biệt. Hãy xem ví dụ cắt chuỗi nhỏ dưới đây:

var input = ['Resume'];
input.forEach((s) => print(s.substring(0, 3)));
$ dart main.dart
Res

Có vẻ như không có vấn đề gì xảy ra với các ký tự Latin, chúng ta vẫn lấy được đầy đủ 3 ký tự của chuỗi. Tuy nhiên, khi thay đổi input phù hợp với các ký tự thường được sử dụng ở các khu vực khác ví dụ như tiếng việt:

// New input list:
var input = ['Tóm lại', 'Resume', 'Résumé', '이력서', '💼📃'];
$ dart main.dart

Res
Ré
이력서
💼�

Điều này xảy ra bởi vì các ký tự như "ó", "á"... được encode bởi 2 code point, ví dụ "ó" thực ra gồm 2 code point là o và s. Tin tốt là Dart 2.7 giới thiệu một package mới là characters package để xử lý các trường hợp trên. Với characters package chúng ta có thể sửa đoạn code với một chút thay đổi nhỏ như sau:

// Before:
input.forEach((s) => print(s.substring(0, 3)));
// After, using the characters package:
input.forEach((s) => print(s.characters.take(3)));

Bằng cách sử dụng phương thức mở rộng .characters sau đó gọi phương thức take(), bạn có thể lấy được chính xác 3 ký tự đầu.

Null safety

Một vài tháng trước, chúng ta đã được thông báo rằng Dart sẽ hỗ trợ null safety, có thể truy cập đến tham chiếu an toàn mà không gây ra null pointer exception. Đây là một tính năng đáng giá bởi vì đôi khi developer thường quên kiểm tra các giá trị null, điều mà có thể gây ra các lỗi tiềm ẩn trong ứng dụng. Chúng ta hãy cùng quan sát ví dụ dưới đây:

Nếu bạn thử chạy đoạn code này, nó sẽ gặp sự cố với ngoại lệ con trỏ null, bởi vì khi khởi tạo nhân vật "Captain" tại hàm main, ta không truyền vào tham số birthday. Để xử lý trường hợp này chúng ta có thể thấy lợi thế của null safety trên Dart với một số cách xử lý sau:

  1. Khai báo thuộc tính birthday có thể null
    Thay DateTime birthday bằng DateTime? birthday
  2. Khai báo birthyear có thể null khi birthday null
    Thay int birthyear bằng int? birthyear
  3. Hoặc bọc câu lệnh print cuối cùng bằng một lệnh kiểm tra null
    if (birthyear != null) {...}

Đây mới là bản xem trước của tính năng null safety, nó vẫn đang được xây dựng, tuy nhiên với tốc độ release của đội ngũ Dart, tôi tin rằng chúng ta sẽ được sử dụng chính thức nó sớm thôi.

Kết luận

Trong dự án thực tế bạn nên tạo một thư viện chứa các extension methods riêng để có thể tái sử dụng một cách hiệu quả và tích cực sử dụng khai báo Null Safety để giảm thiểu việc phải check null thường xuyên và tạo ra các lỗi tiềm ẩn có thể gây crash ứng dụng.

Ngoài ra, các bạn cũng có thể tham khảo thêm các ý tưởng sử dụng extension methods trong C# tại https://www.extensionmethod.net/

--

--