I am planning to pit Flutter recently, so I will record it here and check it as needed;

Don’t be cool, just do it,

A simple Dart program

// the 🐷 function, where the application starts
main(){
  var number = "Hello World";
  printInteger(number);
}
// Define a function
printInteger(int aNumber){
  print('The number is $aNumber');
}
Copy the code

Important concepts

When learning the Dart language, you should base your learning on the following facts and concepts

  • Anything stored in a variable is an object; All objects correspond to an instance of a class, functions and NULL are objects, and all objects are based on the Object class
  • Dart is strongly typed, but Dart can do type inference, such as the code variable number being inferred to be of type int. To specify that no type is required, use the special type Dynamic
  • Dart supports generics, such as List, List(List of objects of any type)
  • Dart supports the top-level function main(), again bound to a class or object (respectivelyStatic functionsExamples of function). And support for creating functions within functions (nestedLocal function).
  • Dart supports top-level variables
  • Dart does not have the keywords public, protected, and private, and is private relative to the library if it begins with _
  • Ternary operators: condition? Expr1 : expr2
  • Type problems: warnings and errors. Warnings indicate that the code may not work properly, but do not prevent the program from executing. Errors may be compilation or runtime errors.

The keyword

abstract 2 dynamic 2 implements 2 show 1
as 2 else import 2 static 2
assert enum in super
async 1 export 2 interface 2 switch
await 3 extends is sync 1
break external 2 library 2 this
case factory 2 mixin 2 throw
catch false new true
class final null try
const finally on 1 typedef 2
continue for operator 2 var
covariant 2 Function 2 part 2 void
default get 2 rethrow while
deferred 2 hide 1 return with
do if set 2 yield 3

These words should be avoided as identifiers

  • Words with a 1 are context keywords that have meaning only in a specific place, and they are valid identifiers everywhere
  • Those with a 2 are built-in identifiers. These keywords are valid identifiers in most places and cannot be used for type names and import prefixes
  • The ones with the 3 are updates related to asynchronous support that were added after Dart 1.0 as restricted class reserved words.

variable

var name = "345"; // Create a variable and initialize
dynamic name = "345"; // Name is inferred to be a String
String name = "345";// Explicitly declare
Copy the code

Dynamic: This type has all the possible properties and methods. A variable is decorated with dynamic, which tells the system I know what this type is. The type of the data is not inferred at post-compile time, but at runtime.

The default value

The default value for uninitialized variables is NULL, even for numeric types. Everything is an object in Dart

Final and Const

Variables that are never modified during use can be final or const. The value of a final variable can only be set once; const variables are fixed at compile time.

Built-in types

  • Number: there are two types: 1, int, integer value not greater than 64 bits; Double A floating-point double

  • The String: : Dart String is a sequence of UTF-16 units. The String is created using either single or double quotation marks

    You can use + to concatenate strings into one; Multi-line string objects can be created using three or three double quotes

    Using the r”” prefix, you can create “raw string”

  • Boolean: true and false

  • List :(also known as Array)

    var list = [1, 2, 3]; var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2);

    list[1] = 1; assert(list[1] == 1);

    Add the const keyword before list to define compile-time constants of type list

    var constantList = const [1, 2, 3];
    Copy the code
  • Map: used to associate keys and values. A key can appear only once in a Map

    var gifts = {
      // Key:    Value
      'first': 'partridge',
      'second': 'turtledoves',
      'fifth': 'golden rings'
    };
    Copy the code
  • Set: A Set is a unique Set of elements

    var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; var names = <String>{}; // Set<String> names = {}; // This is ok. // var names = {}; // This creates a Map instead of a Set. var elements = <String>{}; elements.add('fluorine'); elements.addAll(halogens); var gifts = Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';Copy the code
  • Rune: (used to represent Unicode characters in strings)

    In Dart, Rune is used to represent UTF-32 encoded characters in strings

    A common way to indicate a Unicode encoding is, \uXXXX, where XXXX is a 4-bit hexadecimal number. For example, the heart symbol (♥) is \ U2665. For special cases that are not four values, place the coded value in curly braces. For example, the smiley face (�) is \u{1f600}.

  • Symbol

    The Symbol object represents the declared operator or identifier in the Dart program, and you won’t normally use it

Null-aware

Dart null-aware comes from the official Dart 1.12 release, and it is reasonable to have such an operator, which means it saves our code to some extent

The entire operator is dedicated to handling null values, which provide operations on null Pointers

// if b is not null, then b is assigned to A, otherwise C is assigned to A
a = b ?? c;

// If a is null, b is assigned to A
a ?? = b;

// Fun is called when x is not nula? .fun();Copy the code

function

Dart is a true object-oriented language, even functions are objects and have their own type functions. This means functions can be assigned to variables or passed as arguments to other functions, or instances of the Dart class can be called as methods

// omit the type declaration, the function can be used normally
isNoble(atomicNumber) {
  return_nobleGases[atomicNumber] ! =null;
}
// If you have only one sentence, you can write succinct
bool isNoble(intatomicNumber) => _nobleGases[atomicNumber] ! =null;

Copy the code

=> *expr* syntax {return *expr*; }. The => notation is sometimes called arrow syntax, where an arrow can only be followed by an expression;

  • This parameter is optional when invoked

When defining functions, use {param1,param2… }, at the end of the argument list, to specify optional arguments, for example

const Scrollbar({Key key, @required Widget child,bool bold})
Copy the code

Using @required indicates that the parameter is a named parameter of required nature.

  • Location This parameter is optional

    String say(String from, String msg, [String device]) {
      var result = '$from says $msg';
      if(device ! =null) {
        result = '$result with a $device';
      }
      return result;
    }
    Copy the code

    Place the parameter in [] to indicate that the parameter is optional. Indicates that the parameter can not be transmitted

  • Default Parameter Value

    // bold is true; Hidden value is false.
    void abc(bool bold = false);
    Copy the code
    void doStuff(
        {List<int> list = const [1.2.3].Map<String.String> gifts = const {
          'first': 'paper'.'second': 'cotton'.'third': 'leather'{}}})Copy the code

    Accepts a list and map and specifies default values for the parameters

  • The main () function

    void main(){
    }
    Dart args. Dart 1 test
    void main(List<String> arguments) {
      print(arguments);
    }
    Copy the code

    The main function returns a null value and takes an optional List

  • Anonymous functions

    Dart can create functions that have no names. These functions are called anonymous functions. ** is sometimes called a lambda or closure. ** Anonymous functions can be assigned to a variable, for example, anonymous functions can be added or removed from a collection

    main(){
      var list = [];
      list.add(1);
      list.add(2);
      list.add(3);
      list.add(4);
      
      list.forEach((num) {print('the position:${list.indexOf(num)}; Value:$num');
      });
    }
    
    Copy the code

    The above defines an anonymous function with no type parameter num. The list is called each time and the value is passed to the anonymous function.

    If there is only one sentence, write as follows:

    list.forEach((num) = >print('the position:${list.indexOf(num)}; Value:$num'));
    Copy the code
  • Assignment and passing of functions

    main(){
      // Assign an anonymous function to a variable
      var one = (num) = >print('value:$num');
      one(10);
      
      // Assign a normal function to a variable
      var two = abc;
      two(20);
      
      // Pass anonymous functions to ordinary functions
      abc2((str) => print("abc $str"));
    }
    
    void abc2(fun(String str)){
     fun("Output -------");
    }
    
    void abc(num) {print("Hahaha:$num");
    }
    Copy the code
  • Lexical scope

    Dart is a lexical scoped programming language.

    Simply put, the scope of a variable is defined at the time of writing the code, and the visible scope of the variable is in curly braces

    bool topLevel = true;
    
    void main() {
      var insideMain = true;
    
      void myFunction() {
        var insideFunction = true;
    
        void nestedFunction() {
          var insideNestedFunction = true;
    
          assert(topLevel);
          assert(insideMain);
          assert(insideFunction);
          assert(insideNestedFunction); }}}Copy the code

    All variables can be accessed internally, up to the variables in the top-level scope.

  • Lexical closures

    A closure is a function object. Even if a function is called outside its original scope, it can still access variables in its lexical scope

    /// Returns a function whose arguments are added to [addBy].
    Function makeAdder(num addBy) {
      return (num i) => addBy + i;
    }
    
    void main() {
      // create a function that adds 2.
      var add2 = makeAdder(2);
    
      // create a function that adds 4.
      var add4 = makeAdder(4);
    
      assert(add2(3) = =5);
      assert(add4(3) = =7);
    }
    Copy the code
  • Tests whether the functions are equal

    void foo() {} // Top-level function
    
    class A {
      static void bar() {} // Static method
      void baz() {} // Sample methods
    }
    
    void main() {
      var x;
    
      // Compare top-level functions.
      x = foo;
      assert(foo == x);
    
      // Compare static methods.
      x = A.bar;
      assert(A.bar == x);
    
      // Compare instance methods.
      var v = A(); // The first instance of A
      var w = A(); // Instance number 2 of A
      var y = w;
      x = w.baz;
    
      // The same instance referenced by both closures (number 2),
      // So they are equal.
      assert(y.baz == x);
    
      // Two closures reference different instances,
      // So they are not equal.
      assert(v.baz ! = w.baz); }Copy the code
  • The return value

    All functions return a value. If there is no explicit return value, the function implicitly adds a return NULL. statements

Extension functions, attributes

StringExtension:extension StringExt on String {
  double toDouble() {
    return double.parse(this);
  }
  int toInt() {
    return int.parse(this); }}ObjectExtension:extension ObjectExt on Object {
  bool isNullOrEmpty() {
    if (this is String)
      return (this as String).isEmpty;
    else if (this is 可迭代) return (this as 可迭代).isEmpty;
    return this= =null; }} Generic extension:extension AllExt<T> on T {
  T apply(f(T e)) {
    f(this);
    return this;
  }

  R let<R>(R f(T e)) {
    return f(this); }}// Extend attributes
extension SizeExtension on num {

  double get w => 10.0;

  double get h => 10.0;
}


Copy the code

The operator

  • Dart defines the following operators:

    Description Operator
    One yuan suffix *expr*++ *expr*-- (a) [] . ? .
    One yuan prefix -*expr* ! *expr* ~*expr* ++*expr* --*expr*
    multiplicative * / % ~ /
    additive + -
    shift << >> >>>
    bitwise AND &
    bitwise XOR ^
    bitwise OR `
    relational and type test > = > < = < as is is!
    equality = = ! =
    logical AND &&
    logical OR `
    if null ??
    conditional *expr1* ? *expr2* : *expr3*
    cascade .
    assignment = * = / = + = - = & = ^ = etc.

    In the table above, most operators can be overloaded

  • Conditional expression

    *condition* ? *expr1* : *expr2*
    Copy the code

    If the condition is true, execute expr1 (and return its value) : otherwise, execute and return the value of expr2.

    *expr1* ?? *expr2*
    Copy the code

    Return the value of expr1 if expr1 is non-null; Otherwise, execute and return the value of expr2.

  • Cascade operator

    Cascade operators can perform operations on an object, call functions, and access field properties on the same object.

    void main() {
      newA() .. a1() .. a2(); }class A{
    	void a1(){
    		print('a1');
    	}
    	
    	void a2(){
    		print('a2'); }}//a1 a2
    Copy the code

    Cascade operators can be nested

    finaladdressBook = (AddressBookBuilder() .. name ='jenny'
          ..email = '[email protected]'. phone = (PhoneNumberBuilder() .. number ='415-555-0100'
                ..label = 'home')
              .build())
        .build();
    Copy the code

Control flow statement

  • if and else

  • for loops

    for (var i = 0; i < 5; i++) {
      message.write('! ');
    }
    Copy the code

    You can also use forEach, or for-in

    candidates.forEach((candidate) => candidate.interview());
    Copy the code
    var collection = [0.1.2];
    for (var x in collection) {
      print(x); / / 0 1 2
    }
    Copy the code
  • while and dowhile loops

  • break and continue

  • switch and case

    Similar to Java, you can compare integers, strings, or compile-time constants to the same instance (and not subclasses), and enumerations can use switch statements

  • assert

    If the Boolean condition in Assert is false, the normal program execution flow is interrupted

    Assert statements are valid only in the development environment, not in production

abnormal

Dart can throw and catch exceptions, or if none are caught, they will be thrown, ultimately causing the program to terminate

Unlike Java, all exceptions in Dart are not checked for exceptions. Methods do not declare the exceptions they throw, nor are they required to catch any

Dart provides the Exception and Error types, as well as several subtypes. You can also customize the exception type. In addition, the Dart program can throw any non-NULL object, not just Exception and Error objects.

  • throw

    throw FormatException('Expected at least 1 section');
    Copy the code
  • Throw an arbitrary object

    throw 'Out of llamas! ';
    Copy the code
  • Throw an exception where the expression is used

    void distanceTo(Point other) => throw UnimplementedError();
    Copy the code
  • Catch

    Catch exceptions

    try {
      breedMoreLlamas();
    } on OutOfLlamasException {
      // a special exception
      buyMoreLlamas();
    } on Exception catch (e) {
      // Any other exceptions
      print('Unknown exception: $e');
    } catch (e) {
      // No specified type, handle all exceptions
      print('Something really unknown: $e');
    }
    Copy the code

    The catch function can specify 1 or 2 parameters, the first being the exception object and the second being the StackTrace object.

    try {
      / /...
    } on Exception catch (e) {
      print('Exception details:\n $e');
    } catch (e, s) {
      print('Exception details:\n $e');
      print('Stack trace:\n $s');
    }
    Copy the code

    If some exceptions need to be handled, you can use rethrow to rethrow the exception

    void misbehave() {
      try {
        dynamic foo = true;
        print(foo++); // Runtime error
      } catch (e) {
        print('misbehave() partially handled ${e.runtimeType}. ');
        rethrow; // Allow callers to see the exception.}}void main() {
      try {
        misbehave();
      } catch (e) {
        print('main() finished handling ${e.runtimeType}. '); }}Copy the code
  • finally

    Finally is executed whether or not an exception is tried. If a try holds an exception, the corresponding catch is executed first, and finally

class

Dart is an object-oriented language based on class and mixin inheritance. Each Object is an instance of a class, and all classes inherit from Object. Based on * Mixin inheritance * means that each class (except Object) has only one superclass, and code in one class can be reused in multiple other inherited classes.

  • Create an object

    var p = Point(2.2);
    
    // Set the value of the instance variable y.
    p.y = 3;
    
    // Get the value of y.
    assert(p.y == 3);
    
    // If p is not empty, set y=8p? .y =8
    
    // Call p's distanceTo() method.
    num distance = p.distanceTo(Point(4.4));
    Copy the code

    Use? . Instead of. To avoid exceptions caused by the possibility that the left object is null

  • Getting the object type

    The Type of the object can be obtained at runtime using the object’s runtimeType property, which returns a Type object.

  • The instance variables

    class Point {
      num x; // Declare a sample variable x with an initial value of null.
      num y; // Declare the example variable y with an initial value of null.
      num z = 0; // Declare a sample variable z with an initial value of 0.
    }
    Copy the code

    Uninitialized variables are null

    Getter methods are implicitly generated for all instance variables, and setter methods are generated for non-final variables

  • The default structure

    Dart provides a default construct when no construct is declared

  • Constructors are not inherited

    Subclasses do not inherit the constructor of their parent class. A subclass does not declare a constructor, so it has only a default constructor (anonymous, no arguments).

  • Named constructor

    We can use named constructors to implement multiple constructors for a class. We can also use named constructors to more clearly indicate the purpose of a function:

    class Point {
      num x, y;
    
      Point(this.x, this.y);
    
      // Name the constructor
      Point.origin() {
        x = 0;
        y = 0; }}Copy the code

    Remember that constructors cannot be inherited, which means that the named constructor of the parent class cannot be inherited by subclasses. If you want to create a subclass using a named constructor defined in the parent class, you must implement that constructor in the subclass.

  • Call the parent field default constructor

    The execution sequence is as follows:

    1. Initializer List (List of initialization parameters)
    2. Superclass’s no-arg constructor (nameless constructor for superclass)
    3. Main class’s no-arg constructor main class’s no-arg constructor
    class Person {
      String firstName;
    
      Person.fromJson(Map data) {
        print('in Person'); }}class Employee extends Person {
      // Person does not have a default constructor;
      // you must call super.fromJson(data).
      Employee.fromJson(Map data) : super.fromJson(data) {
        print('in Employee');
      }
    }
    
    main() {
      var emp = new Employee.fromJson({});
    
      // Prints:
      // in Person
      // in Employee
      if (emp is Person) {
        // Type check
        emp.firstName = 'Bob';
      }
      (emp as Person).firstName = 'Bob';
    }
    Copy the code
  • Constant constructor

    If your class creates objects that never change, you can create constant instances at compile time, define constant constructors, and make sure that all member variables are final.

    var p = const ImmutablePoint(2.2);
    Copy the code

    Create a compile-time constant by prefacing the constructor name with a const shutdown word

    Note: Constructing two identical compile-time constants produces an identical instance

    In the context of constants, const can be omitted:

    // There are many const keywords here.
    const pointAndLine = const {
      'point': const [const ImmutablePoint(0.0)].'line': const [const ImmutablePoint(1.10), const ImmutablePoint(2 -.11)]};Copy the code
    // There is only one const that establishes the constant context.
    const pointAndLine = {
      'point': [ImmutablePoint(0.0)].'line': [ImmutablePoint(1.10), ImmutablePoint(2 -.11)]};Copy the code

    In Dart2, a const keyword in a constant context can be omitted

    class ImmutablePoint {
      static final ImmutablePoint origin =
          const ImmutablePoint(0.0);
    
      final num x, y;
    
      const ImmutablePoint(this.x, this.y);
    }
    Copy the code
  • Factory constructor

    class Logger {
      final String name;
      bool mute = false;
    
      // As can be seen from the named _,
      // _cache is private.
      static final Map<String, Logger> _cache =
          <String, Logger>{};
    
      factory Logger(String name) {
        if (_cache.containsKey(name)) {
          return _cache[name];
        } else {
          final logger = Logger._internal(name);
          _cache[name] = logger;
          return logger;
        }
      }
    
      Logger._internal(this.name);
    
      void log(String msg) {
        if(! mute)print(msg); }}Copy the code

    In fact, it is a factory pattern, pass as the name of the corresponding, and then get the corresponding instance

  • About the others

    Abstract classes, enumerations, I’m not going to go into detail here, these are all basic operations, just like Java. If you do not understand, you can go to the official website to check

Asynchronous operations

  • Future

    void main() {
      print("start ----------->");
      print(getNetData());
      print("end -------------->");
    }
    
    String getNetData() {
      // Takes 3 seconds
      sleep(Duration(seconds: 3));
      return "Network data";
    }
    Copy the code
    Start -- -- -- -- -- -- -- -- -- -- - > F / / takes three seconds, printed below Network data end -- -- -- -- -- -- -- -- -- -- -- -- -- -- >Copy the code

    As you can see, the main method blocks directly, preventing subsequent code execution, which must be a problem

    Asynchronous network request

    Future<String> getNetData() {
      return Future(() {
        sleep(Duration(seconds: 3));
        return "Network data";
      });
    }
    Copy the code
    start ----------->
    Instance of 'Future<String>'
    end -------------->
    Copy the code

    The future object is used to place time-consuming operations in functions that pass in parameters

    You can see that there is no blocking, but the result returned is an instance of the Future. With a future, you can isolate time-consuming operations without affecting the execution of the main thread.

    Get the result of the future

    // When a future returned by getNetData returns a result, the function passed in then is automatically called
    // This function will be executed in an event loop
    getNetData().then((value) {
      print(value);
    });
    Copy the code
    Start -----------> end --------------> Network dataCopy the code

    Exceptions during execution

    getNetData().then((value) {
      // Support succeeded here
      print(value);
    }).catchError((error) {
      // Execution failed up to this point
      print(error);
    });
    Copy the code

    Common methods

    • Future.whenComplete

      Whether the execution succeeds or fails it ends up here

      getNetData().then((value) {
        // Support succeeded here
        print(value);
      }).catchError((error) {
        // Execution failed up to this point
        print(error);
      }).whenComplete(() => print("Complete"));
      Copy the code

      Can be used to do some close dialog box operations

    • Future.them chain call

      // Return values can be followed in them, which will be returned in the next chained then call
      getNetData().then((value) {
        // Support succeeded here
        print(value);
        return "data1";
      }).then((value) {
        print(value);
        return "data2";
      }).then((value) {
        print(value);
      }).catchError((error) {
        // Execution failed up to this point
        print(error);
      }).whenComplete(() => print("Complete"));
      Copy the code
      Network data data1 data2 completedCopy the code
    • Future.wait

      If you want to wait until multiple asynchronous tasks have finished to do something, you can use future.wait

      Future.wait([getNetData(), getNetData(), getNetData()]).then((value) {
        value.forEach((element) {
          print(element);
        });
      });
      Copy the code

      Wait takes an array of type Future and executes then only after all the futuresof the array have been successfully executed

    • Future.delayed

      The function is executed after a certain time delay

       Future.delayed(Duration(seconds: 3), () {
          return "Message in three seconds.";
        }).then((value) {
          print(value);
        });
      Copy the code
  • Async and await

    Async: Refers to functions that are asynchronous. The defined function returns a Future object. Callbacks can be added using then

    “Await” : a Future means to await the completion of an asynchronous task. After the async task is completed, the async task will go further. “await” must appear inside async

    void main() {
      print("start ------ ----->");
    
      getNetData().then((value) => print(value));
    
      print("end -------------->");
    }
    
    Future<String> getNetData() async {
      var result1 = await Future.delayed(Duration(seconds: 3), () {
        return "Network Data 1";
      });
      var result2 = await Future.delayed(Duration(seconds: 3), () {
        return "Network Data 2";
      });
      return result1 + "-- -- -- -- --" + result2;
    }
    Copy the code
In getNetData, take two results, concatenate them, and return them together. The return value is wrapped in a Futter, and you can get the results directly using them at the call point. The official document, the Flutter of actual combat, Dart asynchronous (https://juejin.cn/post/6844903942795558919#heading-11) under the # # let us > happy codeingCopy the code