When LEARNING Flutter, I thought I could easily master Dart, but I often found that I didn’t understand the grammar. So I decided to learn the DART in earnest. There are a lot of learning materials on the Internet. I studied mainly from the official website, and then found a video to supplement my study.

The code covered in this article can be found on my Github.

  • Read the Chinese document first. After all, the mother tongue is Chinese, which is good for quick understanding. Learn what you already know and what is new. This time I’m just going to look at it, not code it.
  • Make a mind map. Use a mind map to create a clear sequence of events as you watch it for the first time. It doesn’t have to be too complicated, just add each headline and sub-headline. We’ll fill it up later.
  • Read the English document the second time. Because the first time, have an impression of the document, and then look at the English document will be easier. Mainly in order to strengthen their English reading ability, so see more, slowly also remember more.
  • The second time, encounter not new words, or high-frequency words, write down, expand their vocabulary. If you can’t remember it now, know it first.
  • The second time will also be a code walkthrough. I don’t have the talent to understand all of it when I look at the documentation, which only gives some code examples, or pseudo-code. So this time, we will walk through all the code involved in the document.
  • For the second time, I need to do two things. One way to do that is to supplement the mind maps we’ve done before and do a complete. The other thing is to sort out your study notes, which I’m writing here. The content of notes mainly record their own learning content.
  • Third time, watch the video. This last time, is to check the missing, sometimes there is not in the document, in the video can also involve a lot of, timely supplement. In addition, the most important point of the video is that there are some places to read the document, write code did not understand, the video just involved, a little listen, you will understand. Of course, the video is quite long, as long as it is learned before, you can skip to watch.

In fact, it is more time-consuming to learn, but I think it is still a solid foundation, do not miscut wood. Sometimes when you’re working on a project, when you’re dealing with the details, it’s ambiguous. Even sometimes see a piece of code, and did not contact, and then go to Baidu, check the document, although there was an impression, but knowledge is not systematic.

Environment set up

1. Install the Dart SDK

My computer is a Mac, so I need Homebrew installed. The problem I ran into here was that the download kept failing. Finally, the Internet was downloaded successfully through science.

Then follow the examples provided on the website to install dart.

Dart –version Indicates that the DART version is successfully installed.

2. Configure the Dart plug-in for the editor

I use VS Code for the Dart environment. It’s very simple, just install the Dart plug-in.

  • Code Runner: Runs the Dart plug-in in VS Code
  • Dart: is the core plug-in

Write a test file: test.dart

void main(){
  Dart is similar to Java and requires an entry main function
  print('123');
}
Copy the code

If the preceding command output is displayed, the Dart environment is configured.

Note:

  • The naming convention for files in DART is to use an underscore delimiter, for exampletest_helloInstead of using the name hump. Check out the official specification manual.

Important concepts

  • All variables refer to objects, and each object is an instance of a class. Numbers, functions, and NULL are all objects. All classes inherit from the Object class.

  • Although Dart is a strongly typed language, specifying a type when declaring a variable is optional because Dart can do type inference. In the code above, the type of the variable number is inferred to be int. If you want to explicitly declare an indeterminate type, you can use the special type Dynamic.

  • Dart supports generics, such as List (representing a List of int objects) or List (representing a List of objects of any type).

  • Dart supports top-level functions (such as the main method) as well as defining functions that belong to classes or objects (that is, static and instance methods). You can also define functions (nested or local) within functions.

  • Dart supports top-level variables, as well as variables (static and instance variables) that are defined as belonging to classes or objects. Instance variables are sometimes called fields or properties.

  • Dart does not have the public, protected, and private member access qualifiers that Java does. An identifier that begins with an underscore (_) is private in the library. Consult libraries and visibility for more information.

  • An identifier can start with a letter or underscore (_) and can be followed by a combination of characters and numbers.

  • Dart distinguishes expressions from statements in that expressions have values and statements do not. Like the conditional expression condition? Expr1: expr2 contains the value expr1 or expr2. In contrast to if-else branch statements, if-else branch statements have no value. A statement usually contains one or more expressions, but an expression cannot contain only one statement.

  • The Dart tool displays both warning and error types of problems. Warnings indicate that there may be a problem with the code but do not prevent it from running. Errors are classified as compile-time errors and runtime errors; Compile-time error code does not run; Runtime errors cause exceptions while the code is running.

variable

Variable definitions

// Variables store only references to objects
var name = 'Bob'; 

// Uninitialized variables have a default initialization value of null. This is true even for numbers, because everything is an object in Dart, and numbers are no exception.
int lineCount;
assert(lineCount == null);

Copy the code

Final and const

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

// The const keyword can be used not only to define constants, but also to create constants
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to 'const []' (Equivalent to 'const []')

// You can also use type checking in variables

Valid compile-time constants as of Dart 2.5.
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if (i is int) i: "int"}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; / /... and a spread

Copy the code

Built-in types

Numbers

Dart two data types :int and double

Here’s how strings and numbers are converted:

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String and preserves the specified decimal number
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
Copy the code

Strings

Use single or double quotation marks for definitions

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";
Copy the code

Strings can be concatenated using + or directly next to each other

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
    
var s2 = 'The + operator ' + 'works, as well.';
Copy the code

You can create a multi-line string using either three single quotes or three double quotes:

var s1 = You can create multi-line strings like this. ' ' ';

var s2 = """ This is also a multi-line string. "";
Copy the code

Any compile-time constant can be used as an interpolation for string literals

void main(List<String> args) {
  
// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1.2.3];

const validConstString = '$aConstNum $aConstBool $aConstString';
print(validConstString);

// Non-compile-time variables, cannot be assigned
// const invalidConstString = '$aNum $aBool $aString $aConstList';

var invalidConstString = '$aNum $aBool $aString $aConstList'; // Compile-time variable, which can be assigned

}
Copy the code

String Common attributes:

  • length
  • isEmpty
  • isNotEmpty
void main(List<String> args) {
  String a = '123'; 
  print(a.length); / / 3
 
  print(a.isEmpty); // false

  print(a.isNotEmpty);  // true
}
Copy the code

String Common attributes

  • contains
  • subString
  • startsWith
  • endsWith
  • indexOf
  • lastIndexOf
  • toLowerCase
  • toUpperCase
  • trim
  • trimLeft
  • trimRight
  • split
  • replaceXXX

Booleans

Boolean types are true and false only.

void main(List<String> args) {
  var test;

  // Everything in dart is an object, so null is displayed
  if(test == null) {print('test is null'); }}Copy the code

List

Arrays in Dart are represented by List objects.

void main(List<String> args) {
  // 1. List can be mixed
  var list1 = [1.2.3.'4'];
  print(list1);

  // 2. Can only be a list of the specified type
  List<int> list2 = [1.2.3];
  print(list2);

  // 3. Define a compile-time array constant with the const keyword
  List<int> list3 = const [1.2.3];
  print(list3);

  list3[1] = 4; // Error at compile time, cannot be modified

  // 4. Construct an array

  List fixedLengthList = new List(3);
  print(fixedLengthList.length); / / 3

}

Copy the code

Array lengths in Dart resemble JavaScript syntax.

void main(List<String> args) {
  var list = [1.2.3.4];

  print(list.length); // true

  print(list[1] = =2);  // true

  list[2] = 4;
  print(list);  // [1, 2, 4, 4]
}
Copy the code

Dart added extension operators

void main(List<String> args) {
  var list1 = [1.2.3.4.5];
  var nullList;
  / / use... Extension list inserts into another list
  var list2 = [0. list1];print(list2); // [0, 1, 2, 3, 4, 5]

  / / use... ? If nullList is empty, it is not inserted
  var list3 = [0. ? nullList];print(list3);
}
Copy the code

Dart can also use Collection If and Collection for to create arrays based on conditions.

void main(List<String> args) {

  // create an array dynamically based on the test condition
  var test = true;

  var list = [
    1.2.3.if(test) 4
  ];

  print(list);    // [1, 2, 3, 4]

  /// You can also create an array by looping through another array
  var arrays = [1.2.3.4];

  var location = [
    '# 0'.for(var i in arrays) '#$i'
  ];

  print(location);    // [#0, #1, #2, #3, #4]
}
Copy the code

List Common operations

void main(List<String> args) {
  var a = [1.2.3];
  a.add(4);
  print(a); // [1, 2, 3, 4]

  a.insert(1.100);
  print(a);   // [1, 100, 2, 3, 4]

  a.remove(4);
  print(a);   // [1, 100, 2, 3]

  // Shuffle the order
  a.shuffle();
  print(a); // [2, 3, 100, 1]

  print(a.asMap()); // {0: 1, 1: 100, 2: 2, 3: 3}

  / / sorting
  List<String> numbers = ['two'.'three'.'four'];
  // Sort from shortest to longest.
  numbers.sort((a, b) => a.length.compareTo(b.length));
  print(numbers);  // [two, four, three]
  
  / / interception
  a.sublist(1);
  print(a);

  // You can call print directly, or customize other functions
  numbers.forEach(print);
}

Copy the code

Sets

To create sets.

void main(List<String> args) {
  var names = <String> {};// create a Set of type +{}.
  Set<String> names2 = {}; // Create a Set (This works, too) in the form of a type variable.
  var names3 = {}; // This Creates a Map rather than a Set (Creates a Map, not a)

  print(names.runtimeType); // _CompactLinkedHashSet<String>
  print(names3.runtimeType); // _InternalLinkedHashMap<dynamic, dynamic>
}
Copy the code

Note: Dart creates an object of type Map

if you forget to comment a type on {} or assign a value to an untyped variable.
,>

Maps

Create a Map

void main(List<String> args) {

  String 
      
        test = {}
      
  var test = {
    'a': '1'.'b': '2'.'c': '3'
  };

  // You can instantiate an object without using the keyword New
  var gifts = Map(a); gifts['first'] = 'partridge';
  gifts['second'] = 'turtledoves';
  gifts['fifth'] = 'golden rings';

}
Copy the code

Operating Map

void main(List<String> args) {
  var map = {'a': 1.'b': 2.'c': 3};

  print(map.length); / / 3

  print(map.isNotEmpty); // true

  print(map.isEmpty); // false

  print(map.keys); // (a, b, c)

  print(map.values); / / (1, 2, 3)

  print(map.containsKey('c')); // true

  print(map.containsValue(4)); // false

  / / remove
  map.remove('a'); // {b: 2, c: 3}
  print(map);

  map.forEach((key, value) {
    print('key = $key, value = $value');
    // key = b, value = 2
    // key = c, value = 3
  });
}

Copy the code

The operator

Arithmetic operator

I haven’t used the integer operator before, so let me write that down.

void main(List<String> args) {
  print(2 + 3= =5);
  print(2 - 3= =- 1);
  print(2 * 3= =6);
  / / in addition to
  print(5 / 2= =2.5); // The result is a floating point number
  / / integer
  print(5~ /2= =2); // The result is an integer
  / / to take over
  print(5 % 2= =1); / / to take over
  
  print('5/2 = The ${5~ /2} r The ${5 % 2}'= ='5/2 = 2 r 1');
}

Copy the code

Autoincrement and autodecrement

The increment and decrement explanations in the documentation are great.

  • ++var and –var, evaluate the var variable before assigning it to another variable
  • Var ++ and var–, first assign the var variable to another variable and then operate on itself
void main(List<String> args) {
  var a, b;

  a = 0;
  b = ++a; // Increment a by 1 before b is assigned.
  print(a == b); / / 1 = = 1

  a = 0;
  b = a++; // Increment a by 1 after b is assigned.
  print(a ! = b);/ / 1! = 0, a = 1

  a = 0;
  b = --a; // Decrement a by 1 before b is assigned.
  print(a == b); // -1 == -1, a = -1

  a = 0;
  b = a--; // Subtract a by 1 after b is assigned.
  print(a ! = b);/ / - 1! = 0
}

Copy the code

Relational operator

void main(List<String> args) {

  
  print(2= =2);
  print(2! =3);
  print(3 > 2);
  print(2 < 3);
  print(3> =3);
  print(2< =3);
}

Copy the code

Type judgment operator

Obj is T is true if and only if obj implements T’s interface.

void main(List<String> args) {
  Emp emp = Emp();
  Person p = Person('Joe');
    
  print(emp is Person);   // true

}
class Person{
  final _name;

  Person(this._name);
}
class Emp implements Person{
  // Must be implemented
  get _name => ' ';
}

Copy the code

The assignment operator

  • use=To assign a value
  • ?? =To assign a value to a variable whose value is null
void main(List<String> args) {
  var a;
  var b;

  a = 1;
  // Only if b is nullb ?? =2;

  print(a); / / 1
  print(b); / / 2


  var c = 9;
  c ~/= 2;

  print(c); / / 4

}
Copy the code

Logical operator

With logical operators you can reverse or combine Boolean expressions

void main(List<String> args) {
  var flag = true;
  const tab = 0;

  if (flag && (tab == 3 || tab == 0)) {
    print('hello'); // hello}}Copy the code

Conditional expression

  • Consider using if the assignment is based on a Boolean expression? :
  • Is considered if the assignment is based on whether the value is null??
void main(List<String> args) {
  // The ternary operator is good
  String playName(Stringname) => name ! =null ? name : 'Tom';

  / /?? Written in the best
  String playName3(String name) => name ?? 'Tom';

  // if-else bad
  String playName2(String name) {
    if(name ! =null) {
      return name;
    } else {
      return 'Tom'; }}}Copy the code

Cascade operator

Cascade operators (..) Allows you to call variables or methods of multiple objects in succession on the same object.

void main(List<String> args) {
  The cascade operator is not strictly an operator, but a special syntax for DART
  varp = Person() .. name ='tom'
  ..age = 1
  ..say(); // name = tom, age = 1
  // Call the say method directly
}

class Person{
  String name;
  int age;

  void say(){
    print('name = $name, age = $age'); }}Copy the code

Flow control statement

Unlike JavaScript, the condition in Dart’s if statement must be a Boolean value, not another type

The if and the else

void main(List<String> args) {
  var bar = false;
  if (bar ==false) {print('false');
  }else if( bar == true) {print('true');
  }else{
    print('not true or false'); }}Copy the code

The for loop

Dart closures in the loop are captured automatically. The following example outputs two 2’s in JavaScript.

void main(List<String> args) {

  // Closures in the for loop automatically capture the index value of the loop to avoid some common pitfalls in JavaScript
  var list = [];
  for(var i =0; i<2; i++){
    list.add(()=>print(i));
  }
  list.forEach((v) => v());
}
Copy the code

When you don’t need an array index, use forEach

  var prints = [1.2.3];
  prints.forEach((v)=>print(v));
Copy the code

List and Set support for-in

  // List and Set support for-in
  var collections = [1.2.3.4];
  for (var i in collections) {
    print('i = $i');
    print(i);
  }
Copy the code

While and do – the while

  • The while loop evaluates the condition before executing the loop body
  • A do-while loop executes the body of the loop before judging the condition:
void main(List<String> args) {
  var i = 0;
  while (true) {
    ++i;
    print(i); / / 1 2 3
    if (i == 3) break;
  }
  print('i = $i');
  do {
    i++;
    print(i); / / 4 5 6
    if(i == 6)break;
  } while (true);
}

Copy the code

Break and continue

  • Break the loop
  • Continue a loop
void main(List<String> args) {
  for(var i = 0; i<3; i++){
    print(i); // Output 0, 1
    if(i ==1) {// Break the loop
      break;
    }
    print('Hi I was executed'); // Output only once
  }

  for(var i = 0; i<3; i++){
    print(i);// Output 0, 1, 2
    if(i ==1) {// Continue the loop
      continue;
    }
    print('Hi I was executed'); // Output 2 times, the second time is skipped, the loop continues}}Copy the code

The switch and the case

  • The Switch statement uses == in Dart to compare integers, strings, or compile-time constants. The two objects must be of the same type and cannot be subclasses and the == operator is not overridden
  • Every non-empty case clause must have a break statement
  • When no case statement matches, the default clause can be used to match the case
  • caseIf the value is empty, the value is adoptedfall-throughIn the form of
  • caseIf the value is not empty, the value is adoptedcontinueAnd the label tag
  • Variables in case are local variables
void main(List<String> args) {
  var name = 'annie';
  switch (name) {
    case 'tim':
      print('tim');
      break;
    case 'peter':
      print('peter');
      break;
    case 'jack': / / fall - through form
    case 'tom':
      print('jack and tom');
      break;
    case 'annie':
      print('annie');
      continue ruth; // Continue with the statement labeled Ruth

    ruth:
    case 'ruth':
      print('ruth');
      break;
    case 'wilson':
      var test = 'test'; // Local variables
      print(test);
      break; }}Copy the code

assertions

  • In a development environment, add assertions to interrupt code execution
  • assertWhether it takes effect depends on the development tool and the framework used, and can be executed from the command linedartThe command
void main(List<String> args) {
  var num = 100;
  // RESULT of results
  // Then an error is reported, and all subsequent content is no longer executed
  assert(num < 10);

  // The second argument can specify an exception error message
  assert(num < 90.'Exception: ($num) > 90');

    Dart does not get an error because it is in production
}
Copy the code

function

The function definitions

void main(List<String> args) {
  
  // It is best to define a return value for a function
  bool isBool(bool flag){
    var test = false;
    return test;
  }
  
  // It is possible to write no return value
  isBool2(bool flag){
    var test = false;
    return test;
  }

  // Use the arrow function
  isBool3(bool flag) => flag = false;
}
Copy the code

This parameter is optional

Although arguments are optional, you can also specify a parameter as required, using @required.

import 'package:meta/meta.dart';

void main(List<String> args) {
  // Define an optional named parameter
  void saySomething({String name, int age}){
    print('name = $name, age = $age');
  }

  // Call optional named arguments without writing {}
  saySomething(name: 'tom', age: 12); // name = tom, age = 12
  saySomething(name: 'cook'); // name = cook, age = null

  The time argument must be passed
  // The meta package must be imported using the @required annotation
  // To import the meta. Dart package, you must declare it in pubspec.yaml
  void playGame({String name,@required int time}){
    print('name = $name, age = $time');
  }

  // Although the @required annotation is used, no error is reported to the application, but a warning is issued
  playGame(name: 'Peace Elite');
}
Copy the code

Location This parameter is optional

Location Optional parameters are indicated by []

void main(List<String> args) {
  
  void say(String name, int age, [String address]){
    if(address == null) {print('name = $name, age = $age');
    }else{
      print('name = $name, age = $age, address = $address');
    }    
  }
  say('tom'.123);  // name = tom, age = 123
  say('tim'.34.'Beijing');   // name = Tim, age = 34, address = Beijing

 
}
Copy the code

The default value

You can use = to set default values for optional parameters

void main(List<String> args) {
  void startEng({bool oil = true.bool state = false{})return print(oil && state);
  }

  startEng(); / / default is false
  startEng(state:true); // true
  startEng(oil:true,state:true); // true

  // What if name is the default, but age is passed?
  String say(String start, String end, [String name = 'jack'.int age]){
    if(name ! =null) {// Never null
      print('start = $start, end = $end, name = $name');
    }
    if(age! =null) {print('start = $start, end = $end, name = $name, age = $age');
    }
  }

  say('Beijing'.'Shanghai'.'Joe');
  say('henan'.'hebei'.'jack'.22);
}
Copy the code

The main function

  • All Dart programs must have an entry pointmainfunction
  • Arguments can be passed on the command line
void main(List<String> args) {
  print(args);

  // No arguments are passed on the command line
  if(args.length == 0)return;

  Dart 1 test dart main
  if(int.parse(args[0= =])1) {print(The first argument is zero${args[0]}');
  }

  if(args.length == 2) {print('the number of arguments is${args.length}'); }}Copy the code

Function as a first-class object

  • Pass a function as an argument to another function
  • Treat the function as a variable
void main(List<String> args) {
  void say(int num) {print('hello dart, and num is $num');
  }

  List<int> list = const [1.2.3.4];

  // Pass a function as an argument to another function
  list.forEach(say);

  // use the function as a variable
  var printName = (v)=>print('you are print $v');
  printName('jack');  // you are print jack

  var printName2 = (v){ return print('another print name function $v'); }; printName2('tom');  // another print name function tom
}
Copy the code

Anonymous functions

  • An anonymous function is a function without a function name
  • Arrow functions can be used when the function body has a single line
void main(List<String> args) {
  var list = [1.2.3.4];

  // Anonymous function
  list.forEach((v) {
    print(v);
  });
  // Arrow function
  list.forEach((v) => print(v));

  List<String> getTime(List list, String times(str)) {
    List<String> tmp = [];
    list.forEach((v) {
      tmp.add(times(v));
    });
    return tmp;
  }

  String times(str) {
    return str * 3;
  }

  var list2 = ['h'.'e'.'l'.'l'.'o'];
  // There is no need to write () when calling times, otherwise it becomes an execution function
  print(getTime(list2, times)); // [hhh, eee, lll, lll, ooo]
}

Copy the code

Lexical scope

bool topLevel = true;

void main() {
  var insideMain = true;

  void myFunction() {
    var insideFunction = true;

    // The inner function can access the outer function variable step by step
    void nestedFunction() {
      var insideNestedFunction = true;

      print(topLevel);
      print(insideMain);
      print(insideFunction);
      print(insideNestedFunction); }}}Copy the code

closure

  • A call to a function object outside its original scope can access variables in its lexical scope
  • A function can enclose variables defined in its scope
void main(List<String> args) {
  // Closure is a function object
  // A function can close variables in its scope, even if the function is called from outside
  Function sum(int add){ // Note that the return value type is a function
    return (i) => add + i;
  }

  // The 1 is add and is enclosed
  var sumAll = sum(1); 

  print(sumAll(1)); / / 2


  // A closure is a function that returns another function
  a(){

    var count = 0;
    void printCount(){
        print(count ++);
    }
    return printCount;
  }

  var fun = a();

  // When you want to access local variables in a method, use closures
  fun(); / / 0
  fun(); / / 1
}
Copy the code

Function equality test

  • Functions of different instances are not equal
  • Static methods, top-level functions, all equal
void foo() {} // define A top-level function

class A {
  static void bar() {} // Define static methods
  void baz() {} // Define instance methods
}

void main() {
  var x;

  // Compare whether the top-level functions are equal.
  x = foo;
  assert(foo == x);

  // Compare static methods for equality.
  x = A.bar;
  assert(A.bar == x);

  // Compare instance methods for equality.
  var v = A(); // instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These two closures refer to the same instance object, so they are equal.
  assert(y.baz == x);

  // These two closures refer to different instance objects, so they are not equal.
  assert(v.baz ! = w.baz); }Copy the code

The return value

  • All functions return values
  • Returns NULL if not specified
void main(List<String> args) {
  // There is no function return value specified here
  // In fact, the editor will report an error if it is specified
  foo(){}

  var test = foo();

  print(test); // null
}
Copy the code

Libraries and visibility

  • useimportKeyword import
  • Dart built-in library to usedart:xxxx
  • Other libraries,package:xxxx
  • Members starting with an underscore (_) are visible only in the code base
  • Each Dart program is a library, even if it is not specified using the keyword library

Library prefix

If two library codes conflict, you can specify the library prefix

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Use the Element class lib1.
Element element1 = Element(a);// Use the Element class lib2.
lib2.Element element2 = lib2.Element(a);Copy the code

Import part of the library

If you want to use only part of the code base, you can import the code base selectively

// Import only foo in lib1. (Import only foo).
import 'package:lib1/lib1.dart' show foo;

// Import all of lib2 except foo.
import 'package:lib2/lib2.dart' hide foo;
Copy the code

annotation

Single-line comments

Single-line comments start with //. Anything between // and the end of the line is ignored by the compiler.

// Single-line comment
Copy the code

Multiline comment

  • Document comments are not ignored
  • Multi-line comments can be nested
  • Multi-line comments to/ *Began to* /At the end. All in/ ** /Is ignored by the compiler
void main() {
  /* * This is a lot of work. Consider raising chickens. Llama larry = Llama(); larry.feed(); larry.exercise(); larry.clean(); * /
}
Copy the code

Documentation comments

  • In a document comment, the Dart compiler ignores all text unless you enclose it in brackets.
/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
class Llama {
  String name;

  /// Feeds your llama [Food].
  ///
  /// The typical llama eats one bale of hay per week.
  void feed(Food food) {
    // ...
  }

  /// Exercises your llama with an [activity] for
  /// [timeLimit] minutes.
  void exercise(Activity activity, int timeLimit) {
    // ...}}Copy the code

In the generated document, [Food] becomes a link to the API documentation for the Food class.

That is, the identifier [Food] can display a link in the generated document.

The type definition

  • Use a typedef to display reserved type information
  • Currently type definitions can only be defined on functions
// Create a custom type
typedef Compare = int Function(Object a, Object b);

/// use type definitions
class SortedCollection {
  Compare compare;  // Custom type

  SortedCollection(this.compare);
}

// Simple incomplete implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);
  print(coll.compare is Function); // true
  print(coll.compare is Compare); // true
}
Copy the code

class

Class declarations

  • Using class declarations
  • Create an object with new, which can be omitted
  • All objects are instances of a class
  • All classes inherit from the Object class

Using class members

  • Class members include functions and data
  • Use (.). To access variables and methods
  • use(? .).Avoid null expressions
void main(List<String> args) {
  Person p = Person();
  p.name = 'tom';
  p.age = 12;
  print(p.name); // tom

  / / /? .
  // P2 cannot be set and printed because it is null
  // But used? .No errors will be reported in the future.Person p2; p2? .name ='jack'; p2? .age =13;
  print(p2? .name);// null
}

class Person{
  String name;
  int age;
}
Copy the code

Using constructors

  • Use the name of the class
  • Use the class name. Identifier
  • Use the identical function to determine whether instances of two classes are equal
void main(List<String> args) {
  // Create an instance from the class
  Person p = Person('tom'.12);
  print(p.name);  // tom
  print(p.age); / / 12

  // Pass the class name. Identifier to create an instance
  Person p2 = Person.fromJson({'name': 'jack'.'age': 13});print(p2.name); // jack
  print(p2.age); / / 13

  Animal a = const Animal('titi'.2);
  Animal b  = const Animal('titi'.2);
  print(a.name);
  print(a.age);

  print(b.name);

  // The two instances are equal
  print(identical(a,b));  // true


}

class Person{
  String name;
  int age;

  Person(this.name, this.age);

  Person.fromJson(Map<String.dynamic> json){
    name = json['name'];
    age = json['age']; }}// Constant constructor
class Animal{
  final String name;
  final int age;

  const Animal(this.name, this.age);
}
Copy the code

The instance variables

  • All uninitialized variables are set to NULL
  • All instance variables implicitly declare a Getter method
  • All non-final variables implicitly declare a Setter method
void main(List<String> args) {
  Point p = Point();
  print(p.x); // Call the Getter for x

  p.y = 1; // Call the Setter for y
  print(p.y); // Call the Getter for y
}
class Point{
  int x,y;
}
Copy the code

The named constructor

void main(List<String> args) {
  Point p = Point.origin();

  print(p.x); / / 0
  print(p.y); / / 1
}
class Point{
  int x,y;
  Point(this.x, this.y);

  // the named constructor
  Point.origin(){
    x = 0;
    y = 1; }}Copy the code

Call the parent class non-default constructor

Call to order

  • 1. Initialize the list
  • 2. The parameterless constructor of the parent class
  • 3. Constructor of the current class

Arguments passed to the superclass constructor cannot use the this keyword.

Use (:) to specify a superclass constructor for a subclass constructor.

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person'); }}class Employee extends Person {.
  // Person has no default constructor
  // You need super.fromjson to display the call
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  / / print:
  // In Person performs the parent class construction first
  // in Employee
  if (emp is Person) {  The emp class extends from Person
    emp.firstName = 'Bob';
  }
  print(emp.firstName); // Bob
  (emp as Person).firstName = 'Jack';
  print(emp.firstName);   // Jack
}
Copy the code

Initialization list

  • Initialize variables before the constructor body is executed
  • Initializer lists are very useful for setting final fields
class Person {
  String firstName;

  // Initializers take precedence over constructors
  Person.fromJson(Map data): firstName = data['firstName'] {
    print(firstName);
  }
}

main() {
  Person p = Person.fromJson({ 'firstName': 'zhangsan'});

}
Copy the code

Setting final fields

import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  // Initializing the list sets the final property, which is very useful
  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

main() {
  var p = new Point(2.3);
  print(p.distanceFromOrigin);  / / 3.605551275463989
}
Copy the code

Redirect constructor

  • Call other constructors in your class
  • No function body
void main(List<String> args) {}

class Point {
  int x, y;
  Point(this.x, this.y);

  // Redirect the constructor
  // Call another constructor form in a function
  Point.origin(int num) : this(num.0);
}

Copy the code

Constant constructor

  • Properties are defined as constant properties with final
  • Constructors are defined as constant constructors using const
void main(List<String> args) {
  Point p = const Point(0.0);
  Point p2 = const Point(0.0);

  Point p3 = Point(0.0);

  // The two instance objects are the same
  print(identical(p, p2)); // true

  // If the instance is not declared const, it will not be equal
  print(identical(p, p3)); // false
}

class Point {
  // Variables must be defined with final
  final num x, y;
  const Point(this.x, this.y); // Constructors are also constants
}

Copy the code

Factory constructor

void main(List<String> args) {
  Person p = Person('tom');
  p.say();    // tom

}
 class Person{
   String name;

  // Must be static
  static final Map<String.dynamic> _cach = Map<String.dynamic> ();factory Person(String name){
     return _cach.putIfAbsent(name, () => Person._init(name));
   } 

   Person._init(this.name);

   void say(){
     print(name); }}Copy the code

methods

Instance methods

Object instance methods have access to instance variables and this.

void main(List<String> args) {
  Person p = Person('tom'.'hello title');
  p.say();
}

class Person{
  String name;
  String title;

  Person(this.name, this.title);

  void say(){
    // You can access variables
    print('name is $name');
    // You can also access this
    print(this.name); }}Copy the code

Getter and Setter

You can use the GET and set keywords to add getters and setters for additional properties

void main(List<String> args) {
  Point p = Point(1.2.3);
  print(p.point); / / 6

  p.point = 0;
  print(p.point);
  print(p.z);
}

class Point {
  int x, y, z;

  Point(this.x, this.y, this.z);

  get point => x + y + z;
  // TODO: why point returns z?
  set point(int num) => z = num + x;
}

Copy the code

Abstract methods

void main(List<String> args) {
  
}
// Define an abstract class
abstract class Person{
  // Define abstract methods
  void doSomething();
}

class Zhangsan extends Person{
  // Implement specific methods
  void doSomething(){

  }
}
Copy the code

An abstract class

void main(List<String> args) {
  var me = Me();
  me.sayHello();
}

abstract class Person{
  String name;
  int age;
  
  void sayHello();
}

class Me extends Person{
  void sayHello(){
    print('hello'); }}Copy the code

Implicit interface

A class implements one or more interfaces and implements the API defined by each interface through the keyword implements.

void main(List<String> args) {

  print(saySomething(Person('Joe')));

  print(saySomething(Man()));

}

String saySomething(Person person) => person.sayName('bill');

class Person {
  String _name;

  Person(this._name);

  String sayName(String name) => '$_name, hello. I am a $name ';
}

class Man implements Person {
  get _name => 'Nobody';

  set _name(String name) => ' '; // Since there are implicit setters, this is also defined

  String sayName(String name) => '$_name, hello. I am a $name ';
}
Copy the code

Extending a class

  • Use extends to extend a class
  • Use super to refer to a parent class
void main(List<String> args) {
  Man man = Man();
  man.sayName();
}

class Person{

  void sayName() => print('hello person');
}

class Man extends Person{

  void sayName() => super.sayName();  // Call the parent method
}
Copy the code

Overriding class member

void main(List<String> args) {
  Man man = Man();
  man.sayName();
}

class Person{

  void sayName() => print('hello person');
}

class Man extends Person{

  @override
  void sayName() => print('hello man'); // Override the instance method
}
Copy the code

Rewriting operator

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  The implementations of the == and hashCode operators are not shown here; see the notes below for details.
  / /...
}

void main() {
  final v = Vector(2.3);
  final w = Vector(2.2);

  assert(v + w == Vector(4.5));
  assert(v - w == Vector(0.1));
}
Copy the code

noSuchMethod

This place is not clear

void main(List<String> args) {
  Man man = Man();
  // man.name;
  // How to use todo?
}

class Person {
  void sayName() => print('hello person');
}

class Man extends Person {
  void sayName() => super.sayName(); // Call the parent method

  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried using a non-existent member:' + '${invocation.memberName}'); }}Copy the code

The enumeration

  • Use enMU definitions
  • Each enumerated value has an index
  • Use values to get all enumerations
  • Enumerations cannot be subclasses
  • Enumerations cannot be mixins
  • You cannot implement an enumeration
  • An enumeration cannot be instantiated explicitly

Use enumerated

void main(List<String> args) {
  
  print(Color.blue);  // Get enumeration

  print(Color.red.index);   // Get the enumeration subscript

  List<Color> colors = Color.values;  // Get all enumerations

  print(colors[2]);

}

enum Color{ // Define enumeration
  red, blue, green
}
Copy the code

Switch the enumeration

void main(List<String> args) {
  var aColor = Color.red;
  // If switch is used, each member of the enumeration must be judged by case
  // Otherwise a warning will be issued
  switch (aColor) {
    case Color.red:
      print('red');
      break;
    case Color.blue:
      print('blue');
      break;
    case Color.green:
      print('green');
      break; }}enum Color {
  // Define enumeration
  red,
  blue,
  green
}

Copy the code

Use mixins to add functionality to classes

  • Mixin is a method pattern for reusing code from a class in multiple inheritance
  • Use the with keyword
  • Use mixin definitions
  • Use on to specify which classes can be used

Overwrite operator basic format:

Return type operator operator (parameter 1, parameter 2...) {implementation body...returnThe return value}Copy the code
void main(List<String> args) {
  Musical musical = Musical();
  musical.doSomethin();
}
mixin Person {
  bool canCook = true;
  bool canSay = false;

  // The mixin pattern cannot define constructors
  // Person();

  void doSomethin() {
    if (canCook == true) {
      print('Can cook');
    } else if (canSay == true) {
      print('Can talk'); }}}class Musical with Person{
  @override
  void doSomethin() {
    // TODO: implement doSomethin
    super.doSomethin();   // Call the parent class directly
    print('I'm a subclass.'); }}Copy the code

Class variables and methods

A static variable

  • Static variables are initialized the first time they are used
void main(List<String> args) {
  print(Person.name); // test static
}
class Person{
  static final String name = 'test static';

}
Copy the code

A static method

  • For some generic or common static methods, you should define them as top-level functions rather than static methods
  • Static methods can be used as compile-time constants
import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    returnsqrt(dx * dx + dy * dy); }}void main() {
  var a = Point(2.2);
  var b = Point(4.4);
  For some generic or common static methods, you should define them as top-level functions instead of static methods.
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}
Copy the code

The generic

Why generics

  • It is common to use a single letter to represent type parameters, such as E, T, S, K, and V
  • Specifying generics properly can help code generation better
  • Using generics reduces code duplication

Code error

void main(List<String> args) {
  var names = List<String> ();// Declare it as an array of strings
  names.addAll(['Seth'.'Kathy'.'Lars']);
  // An error message is displayed
  // names.add(42); // Error
}

Copy the code

Reduce code duplication by declaring a class with generics and letting different types of cache implementations make different concrete implementations of the class.

void main(List<String> args) {}

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

class Acache extends Cache<String> {
  String getByKey(String key) {
    // The implementation is specified
    return 'hello';
  }

  void setByKey(String key, String value) {
    // The implementation is specified
    print(11); }}Copy the code

Use collection literals

void main(List<String> args) {
  List list = <String> ['1'.'2'.'3'];  // A collection of strings
  Set set = <String> {'1'.'2'.'3'}; // A collection of strings
  Map map = <String.int> {'age': 1.'size':12}; // Map
}
Copy the code

Use type-parameterized constructors

void main(List<String> args) {
  // Instead of literals, generics can also be used in the form of constructors
  Map map = Map<String.int> (); }Copy the code

A collection of generic types and the types they contain

void main(List<String> args) {
  List list = List<String> ();// list.addAll(['1','2']); 
  // An error is reported if addAll is used
  list.add('1');
  list.add('2');
  print(list is List<String>); // true

  var names = List<String> (); names.addAll(['the little non-success'.'small fang'.'wang']);
  print(names is List<String>); // true
}
Copy the code

Restrict parameterized types

  • Specify parameter types
  • Do not specify the parameter type, use the default type
  • Error argument type, compilation error
void main(List<String> args) {
  var someBaseClassFoo = Foo<SomeBaseClass>();
  var extenderFoo = Foo<Extender>();

  print(someBaseClassFoo.toString()); // instance of 'Foo
      
       '
      
  print(extenderFoo.toString()); // Instance of 'Foo
      
       '
      

  // If no generics are specified, the default is SomeBaseClass
  var foo = Foo();
  print(foo);
  // Taking a non-someBaseclass type as a generic parameter causes a compilation error
  // var foo = Foo<Object>(); 
}

class SomeBaseClass {}

// We can specify T at will. Usually T, E, S, K, etc
class Foo<T extends SomeBaseClass> {
  // Implement...
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {}

Copy the code

Use generic methods

  • The return type of the function
  • The type of the argument is List
  • The type of a local variable
void main(List<String> args) {
  var list = List<String> (); list.addAll(['1'.'2']);

  var firstValue = first(list);
  print(firstValue);  / / 1
}
T first<T>(List<T> ts) {
  // Handle some initialization or error detection...
  T tmp = ts[0];
  // Handle some extra checks...
  return tmp;
}
Copy the code

Asynchronous support

To deal with the Future

  • Code that uses async and await is asynchronous, but looks a bit like synchronous code
  • You must use await in asynchronous functions with the async keyword
  • Use try, catch, and finally to handle exceptions caused by using await
  • The return value of the await expression is a Future object
  • The Future object represents a “promise” and await expression blocks until the desired object returns
void main(List<String> args) {}
// async is used with await
Future checkVersion() async {
  // Catch an exception with a try-catch
  try {
    var version = await lookUpVersion();
  } catch (e) {
    // What happens when the version cannot be found}}void lookUpVersion() {}

Copy the code

An asynchronous function

void main(List<String> args) {
  
}
// Add async keyword to normal functions
Future<String> lookUpVersion() async= >'1.0.0';


Copy the code

To deal with the Stream

  • Use async and await for loops
  • Using Stream API
  • The expression must be of type Stream
  • Use break and return statements to stop receiving Stream data and break out of the loop
  • 1. Wait until the Stream returns a data
  • 2. Execute the body of the loop with the data returned by Stream 1
  • 3. Repeat procedures 1 and 2 until the Stream data is returned

Can be called class

By implementing the call() method of the class, you allow instances of the class to be used in a manner similar to function calls.

The WannabeFunction class defines a call() function that takes three string arguments. The function body concatenates three strings separated by Spaces and ends with an exclamation point

class WannabeFunction {
  String call(String a, String b, String c) => '$a $b $c! ';
}

var wf = WannabeFunction();
var out = wf('Hi'.'there,'.'gang');

main() => print(out);

Copy the code

Mind mapping

Make a mind map to deepen the impression of learning. You are welcome to correct any mistakes.

The original picture is relatively large, so only one screenshot was uploaded to ensure the speed of opening. If you need hd pictures, you can find them in my source file.


References:

  • Dart Grammar Learning
  • Chinese version of official Document
  • 英文版
  • Dart SDK API Chinese version
  • The first step in Flutter development – Introduction to the Dart programming language