Expand operators (Spread Operators)

The expansion operator… The ability to insert elements from list, set, map literals into a collection. Whether an object can be expanded depends on whether Iterable is inherited, except for the Map collection, where expanding a Map actually calls entries.iterator() of the Map

In real development, we might need to create a new collection, the elements of which usually depend on another existing collection, and then add new elements to the base again, such as:

var args = testArgs.toList() .. add('--packages=${PackageMap.globalPackagesPath}')
  ..add('-rexpanded')
  ..addAll(filePaths);
Copy the code

The above code case, from the official website. The toList() function creates a new collection containing all the elements of testArgs, simplifies the code by making chained calls through the cascade operator, and finally adds all the elements of another collection through addAll

But this is still very cumbersome, so here’s how to simplify the code by using the expansion operator:

Var args = [...testArgs, // by expanding the operator willtestThe Args collection is unpacked and the elements inside are put into Args one by one'--packages=${PackageMap.globalPackagesPath}'.'-rexpanded'. FilePaths // Unpack the filePaths with the expansion operator and put the items in args one by one];Copy the code

Declarative UI is used for Flutter, and imperative style is used for Android/iOS.

What is declarative UI? In a Flutter, if a Widget changes, triggered by the setState function, then the Flutter builds a new Widget instance and Widget subtree. The imperative UI takes the original Widget instance, The instance’s methods are then called to trigger the change rather than creating a new Widget

The code style differences between them are as follows:

// Declarative UI code stylereturnViewB( color: red, child: ViewC(...) ,) // Imperative UI code style b.setColor(red) b.clearChildren() ViewC c3 = new ViewC(...) b.add(c3)Copy the code

The expand operator is widely used in a declarative UI like Flutter. For example, we build a ListView:

Widget build(BuildContext context) {
  return CupertinoPageScaffold(
    child: ListView(
      children: [ //children 就是一个List
        Tab2Header(),
        // buildTab2Conversation()返回值也是一个List
        ...buildTab2Conversation(), 
      ],
    ),
  );
}
Copy the code

The above example uses the expansion operator in a List and in a Map collection, as well, such as combining queryParams and formParams to create a new Map collection

var map = { ... options.queryParameters, ... options.data };Copy the code

The same goes for using the expansion operator in a Set, as in:

var items = [2, 3, 4];
var set= {1, 2... items };Copy the code

Null-aware spread operator (null-aware spread)

The expansion operator mentioned above throws a runtime exception if the expanded object is null

var oops = null;
//NoSuchMethodError: The getter 'iterator' was called on null
var list = [...oops];
Copy the code

If the expanded object may be null, we need to add? To the expansion operator. No. (… ?). :

var oops = null;
var list = [...?oops];
Copy the code

Expand operator semantic analysis

List uses the expansion operator for analysis

var list = [elem_1 ... elem_n] 1. Iterates over all elements in the literal1) assigns the element expression (expansion operator) to value iterates 2) if the iterated element is the expansion operator a) if the nullable expansion operator is used and value is null, directlycontinueIterator c) then iterate over the iterator to append the elements to the collection created above. 3) If the iterator is not an expansion operator, add the elements directly to the collection. In this way, the elements of the collection literal are all in the new collection aboveCopy the code

Other collections such as sets and maps have similar mechanisms

Control Flow Collections

Collection-if /for is a collection of control flow statements that can be used when building collection literals

We mentioned above that Flutter is a declarative UI, for example:

Widget build(BuildContext context) {
  returnRow(children: [// Set literals IconButton(icon: icon (icon.menu)), Expanded(Child: title), IconButton(icon: Icon(Icons.search)), ], ); }Copy the code

If we wanted to add some judgment to the code above, such as displaying the icons.search button only on Android, we might write:

Widget build(BuildContext context) {var buttons = <Widget>[IconButton(icon: Icon(Icons.menu)), Expanded(child: title), ]; // For Android, add a search buttonif (isAndroid) {
    buttons.add(IconButton(icon: Icon(Icons.search)));
  }

  return Row(
    children: buttons,
  );
}
Copy the code

With Control Flow Collection, we can simplify the code by using this class:

Widget build(BuildContext context) {
  returnRow(children: [IconButton(icon: icon (Icons. Menu)), Expanded(Child: title), // If android, add the search buttonif (isAndroid) IconButton(icon: Icon(Icons.search)),
    ]
  );
}
Copy the code

In addition to using if, you can also use else, for example to show the search button on Android, and other platforms to show about the button:

Widget build(BuildContext context) {
  return Row(
    children: [
      IconButton(icon: Icon(Icons.menu)),
      Expanded(child: title),
      if (isAndroid)
        IconButton(icon: Icon(Icons.search))
      else
        IconButton(icon: Icon(Icons.about)),
    ]
  );
}
Copy the code

For example, if we need to generate another set from one set, we might write:

var command = [
  engineDartPath,
  frontendServer,
];
for (var root in fileSystemRoots) {
  command.add('--filesystem-root=$root');
}
for (var entryPointsJson in entryPointsJsonFiles) {
  if (fileExists("$entryPointsJson.json")) {
    command.add(entryPointsJson);
  }
}
command.add(mainPath);
Copy the code

With Control Flow Collection, we can write this for more readability:

var command = [
  engineDartPath,
  frontendServer,
  for (var root in fileSystemRoots) '--filesystem-root=$root'.for (var entryPointsJson in entryPointsJsonFiles)
    if (fileExists("$entryPointsJson.json")) entryPointsJson,
  mainPath
];
Copy the code

The for loop can also be evaluated while building a collection literal:

var integers = [for (var i = 1; i < 5; i++) i]; // [1, 2, 3, 4]
var squares = [for (var n in integers) n * n]; // [1, 4, 9, 16]
Copy the code

When building a Map literal, we might write:

Map<String, WidgetBuilder>.fromIterable(
  kAllGalleryDemos,
  key: (demo) => '${demo.routeName}',
  value: (demo) => demo.buildRoute,
);
Copy the code

Collection-for simplifies our code to something like this:

return {
  for (var demo in kAllGalleryDemos)
    '${demo.routeName}': demo.buildRoute,
};
Copy the code

Collection if-for can also be combined, such as for loop nesting, for-if nesting:

//for-for
[for (var x in hor) for (var y in vert) Point(x, y)]

//for-if
[for (var i in integers) if (i.isEven) i * i]
Copy the code

conclusion

Dart expansion operators (null-aware spread, non-null-ware spread) and Control flow collections(Collection if/for)

Let’s make our code more readable when we write it

In particular, the writing of Flutter UI is more in line with the declarative style code style

As you can see, the Dart code is very expressive

Reference

So much for the Dart expansion operator and Control Flow Collections. For more information about Android, check out my GitHub: github.com/chiclaim/An…

Flutter. Dev/docs/get – st… Github.com/dart-lang/l… Github.com/dart-lang/l…


To contact me

The following is my public number, dry goods articles not bad, there is a need to pay attention to, there are any questions can contact me: