Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn Language

Records and patterns in Dart: what they replace

Before records, returning two values from a function meant one of three unappealing options: a class you use once, a List<Object> you index into, or two out-parameters via a wrapper. Records make it one line. ({ int width, int height}) measure ( String text) { // ... return (width : 120 , height : 40 ); } final size = measure ( 'hello' ); print (size.width); That is the headline feature, and it is the smallest part of what records and patterns changed. Records: structural, not nominal A record’s type is its shape. (int, String) and (int, String) are the same type regardless of where they were created, which is what distinguishes a record from a class. // Positional ( String , int ) parseEntry ( String line) { final parts = line. split ( ':' ); return (parts[ 0 ], int . parse (parts[ 1 ])); } // Named — clearer at the call site ({ String name, int score}) parseNamed ( String line) { final parts = line. split ( ':...

Extension types in Dart: a new name for an old value

Every codebase past a certain size has this bug at least once: void transfer ( String fromUserId, String toAccountId, int cents) { ... } transfer (accountId, userId, 500 ); // compiles fine, wrong at runtime Both are String , so the type system has nothing to say. The usual fix is a wrapper class, which costs an allocation on every ID you touch. Extension types are the same fix without the allocation. extension type UserId ( String value) {} extension type AccountId ( String value) {} void transfer ( UserId from, AccountId to, int cents) { ... } transfer (accountId, userId, 500 ); // compile error At runtime, UserId is a String . There is no wrapper object, no field access indirection, nothing allocated. The distinction exists only in the static type system, and is erased before the program runs. What “erased” actually means This is the part that decides whether extension types fit your problem. The compiler replaces the extension type with its representation...

Records and patterns in Dart: what they replace

Before records, returning two values from a function meant one of three unappealing options: a class you use once, a List<Object> you index into, or two out-parameters via a wrapper. Records make it one line. ({ int width, int height}) measure ( String text) { // ... return (width : 120 , height : 40 ); } final size = measure ( 'hello' ); print (size.width); That is the headline feature, and it is the smallest part of what records and patterns changed. Records: structural, not nominal A record’s type is its shape. (int, String) and (int, String) are the same type regardless of where they were created, which is what distinguishes a record from a class. // Positional ( String , int ) parseEntry ( String line) { final parts = line. split ( ':' ); return (parts[ 0 ], int . parse (parts[ 1 ])); } // Named — clearer at the call site ({ String name, int score}) parseNamed ( String line) { final parts = line. split ( ':...

Extension types in Dart: a new name for an old value

Every codebase past a certain size has this bug at least once: void transfer ( String fromUserId, String toAccountId, int cents) { ... } transfer (accountId, userId, 500 ); // compiles fine, wrong at runtime Both are String , so the type system has nothing to say. The usual fix is a wrapper class, which costs an allocation on every ID you touch. Extension types are the same fix without the allocation. extension type UserId ( String value) {} extension type AccountId ( String value) {} void transfer ( UserId from, AccountId to, int cents) { ... } transfer (accountId, userId, 500 ); // compile error At runtime, UserId is a String . There is no wrapper object, no field access indirection, nothing allocated. The distinction exists only in the static type system, and is erased before the program runs. What “erased” actually means This is the part that decides whether extension types fit your problem. The compiler replaces the extension type with its representation...

Dart 3.13 primary constructors: less boilerplate, one real breaking change

Dart 3.13 ships alongside Flutter 3.47, and its headline feature is the one Dart developers have been asking for since the language got null safety: primary constructors are stable . Declare your fields and your constructor in the class header, and delete the three-line ceremony that every model class in your codebase currently repeats. There is also a breaking change hiding in the release, and it is not the one most people expect. The basic shape The traditional form: class Point { int x; int y; Point ( this .x, this .y); } The primary constructor form: class Point ( var int x, var int y); That is the entire class. Note the ordering — the modifier comes first, then the type, then the name: var int x , not int var x . Declaring parameters are the actual feature This is the part worth understanding properly, because it is where the design is subtler than “shorter syntax”. A parameter prefixed with var or final is a declaring parameter : it induces an insta...