Dart type aliases and Record

Article directory

  • Preface
  • Record
    • Record syntax
    • Record usage
        • As function parameters and return values:
        • Anonymous field assignment and named field assignment:
        • Comparison of Record:
  • type alias
  • Summarize

Foreword

In the previous article, we have learned about the common basic types, the use and definition of generics, and the use of collection types in Dart. It can be said that this basically covers most of the types we need for daily development, but there are also other types in Dart There is a type that we also need to understand. It is neither a basic type nor a collection type. It is a separate type, but it is sometimes very useful. It is the Record type. As the name suggests, the record type is used for recording. What is recorded cannot be modified, just like a printed photo. This chapter focuses on introducing this type, and also introduces knowledge about the definition of type aliases.

Record

In Dart, Record is defined as an anonymous, immutable aggregate type. Just like the collection type, it allows you to bind multiple objects to a Record. But unlike the collection type, its size is fixed and it is a heterogeneous type. Heterogeneous types mean that there can be many different types in a Record, unlike collections, where there can only be the same type in a collection. Next, let’s learn how to use the Record type.

Record syntax

In Dart, the way to define a Record is to pass a pair of (), and then separate the values in it through , , so that a Record is defined.

var record = ('first', a: 2, b: true, 'last');

After defining Record, we can use Record. Depending on how Record is defined, the way it is used is also different. Let’s take a look at how to use record in the above code:

print(record.$1); // 'first'
print(record.$2); // 'last'
print(record.a); // 2
print(record.b); // true

As you can see, when we want to access an anonymous field in a Record, we need to use $ plus a serial number to access it. This serial number is worth the number of anonymous fields we want to access, not in the record Which order in the field, and for named fields, you can access them directly by using the name. So Record is very simple to use. But be careful about accessing anonymous fields.

As for why it is accessed in this way, let’s take a look at the type of Record. The type of Record is as follows:

(String,String,{<!-- -->int a,bool b}) record= ('first', a: 2, b: true, 'last');

Dart separates anonymous fields and named fields in Record. Anonymous fields are placed in front and named fields are placed in the back, so we access anonymous fields through the anonymous field.

Record usage

As function parameters and return values:
(int, int) swap((int, int) record) {<!-- -->
  var (a, b) = record;
  return (b, a);
}

In the above code example, we use a Record as the return value and a Record as the parameter. The advantage of this is that we can obtain multiple return values at one time. Here we also see that for a Record we can use destructuring syntax to take out every element in the Record. We’ll talk about this in detail later when we talk about pattern matching. For now, you just need to know what’s going on.

Anonymous field assignment and named field assignment:
//Named field assignment
({<!-- -->int a, int b}) recordAB = (a: 1, b: 2);
({<!-- -->int x, int y}) recordXY = (x: 3, y: 4);
//Anonymous field assignment
(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (3, 4);

You may be confused when you see this. Although both of them have names, why is one an anonymous field and the other a named field. Because in Dart, the way to define anonymous fields is called positional fields, that is, positional parameters, which just occupy a place, just like parameters in functions. Such positional parameters will not It affects the signature of the function, and it can only be accessed through anonymous field access, so this name is actually useless.

But the named field is different. Its type can be regarded as a custom structure. You need to assign values to the corresponding fields in it, otherwise an error will be reported. So we just need to remember that in the type annotation of Record, those enclosed in curly braces and with names are named fields, and the others are anonymous fields.

Another thing to note is that when we do not give specific type annotations and let Dart automatically derive the type of a Record, as long as the given value contains this form identifier:value , then this is a named field, and in this expression, all named fields will form a custom structure type and be placed at the end of the Record. Just like the Record we defined at the beginning.

x var record = ('first', a: 2, b: true, 'last');
//Where a and b conform to the form of named fields, then they will form a {int a, bool b} structure and be placed at the end of the Record.
Record comparison:

The comparison of Records is also divided into comparisons of Records with named fields and comparisons of Records without named fields.

When there is no comparison of named fields, when comparing two Records, first determine whether their types are equal. This type includes how many fields there are and what type each field is. And for Records without named fields, The order of the fields among them is very important. Different orders are different types. After passing the type judgment, the values of the fields are then judged. When all values are equal, then the two Records are equal. .

(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);
print(point == color); // 'true'.

(int x, int y, int z) point = (1, 3, 2);
(int r, int g, int b) color = (1, 2, 3);
print(point == color); // 'false'.

(int x, String y, int z) point = (1, "2", 3);
(int r, int g, String b) color = (1, 3, "2");
print(point == color); // 'false'

(int x, String y, int z) point = (1, "2", 3);
(int r, String g, int b) color = (1, "2", 3);
print(point == color); // 'true'

For Records with named fields, the method of judging anonymous fields is still the same. First, the number, type, order, and value are used to judge anonymous fields. Then judge the named field. The name of the named field is also part of its type, so the named fields must be equal. Then first, the number of fields, field types, and field names must be equal. For named fields, its order It doesn’t matter, because they have names.

({<!-- -->int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({<!-- -->int r, int g, int b}) color = (r: 1, g: 2, b: 3);
print(point == color); // 'false'

({<!-- -->int r, int g, int b}) point = (r: 1, g: 2, b: 3);
({<!-- -->int r, int g, int b}) color = (r: 1, g: 2, b: 3);
print(point == color); // 'true'

(int, int, {<!-- -->int r, int g, int b}) point = (10, 20, r: 1, g: 2, b: 3);
(int, int, {<!-- -->int r, int g, int b}) color = (10, 20, r: 1, g: 2, b: 3);
print(point == color); // 'true'

(int, int, {<!-- -->int r, int g, int b}) point = (10, 20, g: 2, b: 3, r: 1);
(int, int, {<!-- -->int r, int g, int b}) color = (10, 20, r: 1, g: 2, b: 3);
print(point == color); // 'true'

Type alias

When the type annotation of a type is particularly long, and we want to know what type the type is, we want to specify it explicitly instead of relying on Dart’s type inference, or we want to give a type a name that has practical meaning in the current business. , then we can use the typedef keyword to give an alias to a type. The specific usage is as follows:

typedef IntList = List<int>;
IntList il = [1, 2, 3];

And type aliases can also have type parameters, just like generics. Examples are as follows:

typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {<!-- -->};
ListMapper<String> m2 = {<!-- -->};

Another commonly used method is to define a type alias for a function, which can more easily distinguish the role of a certain type of function, and can be used as a type annotation to indicate what kind of function I need. An example is as follows:

typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {<!-- -->
  assert(sort is Compare<int>); // True!
}

Summary

This article describes the use, definition, and comparison methods of Record in Dart, the difference between named fields and anonymous fields, etc. I believe that through this article, you will also have some new understanding of Record in Dart. Finally We also talked about how to alias a type in Dart, and we learned that type aliases in Dart can also have type parameters.

Finally, due to the limited skill of the author, errors will inevitably appear in the article. If you find any errors, please inform the author in time, and the author will modify them as soon as possible to avoid misleading others, respect! .

syntaxbug.com © 2021 All Rights Reserved.