Dart 笔记

Miscellaneous

  • Everything in a variable is an object (except for null in null safety)
  • Can specify dart version in pubspec.yaml. One sdk supports multiple language versions
    yaml
    environment:
      sdk: ">=2.15.1 <3.0.0"
  • _: visible only inside library

Sound null safety

  • All types are non-nullable by default
  • use ? to denote nullable variables
    dart
    int? a = null;
    List<String?> listOfNullableStrings = ['one', null];
  • use ! to assert non-null
    dart
    int c = couldReturnNullButDoesnt()!.abs();
  • late: Tell Dart that a non-null value will be assigned before using the variable
    dart
    class Meal {
      late String _description;
    
      set description(String desc) {
        _description = 'Meal description: $desc';
      }
    
      String get description => _description;
    }
    
    void main() {
      final myMeal = Meal();
      myMeal.description = 'Feijoada!';
      print(myMeal.description);
    }

Variable

  • All variables stores references (including numbers)
  • Default value of nullable variables are null
  • Top-level variables & class variables & late variables are lazily initialized
  • final vs const
    • final: set only once
    • const: compile-time constants (not immutable)

Types

Number

  • int and double
  • num, for both
  • double.parse('1.2')
  • 1.toString()

String

  • single or double quotes
  • String interpolation
    '$variable' or '${expression}'
  • Compare string content: ==
  • Concat: + or adjacent string literal
    dart
    print('Str'
    'ing' == 'Str' + 'ing'); // true
  • Multiline string: triple quotes
  • Raw string (no escape): r'This is a raw string with \n'

Booleans and some logic check

``` dart
print(''.isEmpty);
var a;
print(a == null);
print((0/0).isNaN);
// All true
```

Lists

  • Literal: [1, 2, 3]

  • Compile-time constant: var a = const [''];

  • Spread operator

    dart
    var list1 = [1, 2, 3];
    var list2 = [0, ...list1];  // [0, 1, 2, 3]

    Null-aware spread:

    dart
    var list1;
    var list2 = [0, ...?list1]; // [0]
  • Collection if

    dart
    var list = [1, 2, if (flag) 3];
  • Collection for

    dart
    var list1 = [1, 2, 3];
    var list2 = [
      'obj1',
      for (var i in list1) 'obj${i + 1}'
    ];
    // ['obj1', 'obj2', 'obj3', 'obj4']

Sets, Maps, etc

TODO

Functions

Functions are also object with type Function.

Arrow syntax

=> expr: {return expr;}

Parameter

  • positional parameter
    use [] for optional positional
  • named parameter
    • Define: {Type name}
    • Call: name: value
    • can be marked as required
  • Default value
    Use = value. The value must be compile-time constant.
dart
void test(String pos, {String? name1, required String name2}) {
  print('positional: $pos, named: $name1, required named: $name2');
}

void test2(String pos1, [String? pos2 = 'pos2']) {
  print('positional: $pos1, optional positional: $pos2');
}

test('1', name2: 'name2');
test2('pos1')

Main function

  • Return type: void
    dart
    void main() {
    
    }
  • optional List<String> parameter
    dart
    void main(List<String> arguments) {
      print(arguments);
    }

Anonymous function

dart
var func1 = (String arg1) {
    print(arg1);
};
// Or short version
var func2 = (arg1) => print(arg1);

Lexical scope

Scope of variables is defined statically by layout (curly bracket {}).

Lexical closure

A closure is a function object that has access to variables in its lexical scope.

dart
Function func (List l) {
  return () => print(l);
}

void main() {
  var l = [1, 2, 3];
  var f = func(l);
  f();           // [1, 2, 3]
  l.add(4);
  f();           // [1, 2, 3, 4]
}

Operators

Arithmetic

  • +, -, -expr (negation), *, %
  • / division
  • ~/ integer dividion
  • ++var, --var, var++, var--

Equality & Relational

  • ==: Test equality
    x == y invokes == method on x with arguemnt y (when both non-null).
    Use identical(a, b) to check whether a and b refer to the same object.
  • !=, >, <, >=, <=

Type test

  • as: type cast
  • is: test object against a type
  • is!: not is

Assignment

  • =, op=
  • ??= assign only if null; otherwise keep original value

Logical

  • !, ||, &&

Bitwise & Shift

  • &, |, ^ (XOR), ~
  • >>, <<, >>> (unsigned)

Conditional

  • cond ? expr1 : expr2
  • expr1 ?? expr2: if expr1 is non-null

Cascade notation

  • ..: Used after an object for chain operation.

    dart
    var paint = Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;

    is equavalent to:

    dart
    var paint = Paint();
    paint.color = Colors.black;
    paint.strokeCap = StrokeCap.round;
    paint.strokeWidth = 5.0;
  • ?..: Applied on the first operation => only when not null.

Others

  • ()
  • [], ?[] (null-aware): subscript
  • ., ?. (null-aware): member access

Control flow

If-Else

dart
if () {
} else if () {
} else {
}

For loop

  • Standard for loop
    dart
    for (var i = 0; i < 5; i++) {
    
    }
  • Closures
    Closures inside of Dart’s for loops capture the value of the index.
    dart
    var callbacks = [];
    for (var i = 0; i < 2; i++) {
      callbacks.add(() => print(i));
    }
    callbacks.forEach((c) => c());
    // This will print
    // 0
    // 1
  • Iterable
    dart
    // for-in
    var l = [1, 2, 3];
    for (final n in l) {
      print(n);
    }
    dart
    // forEach
    var l = [1, 2, 3];
    l.forEach(print);

While

while () {} & do {} while ();

Switch

  • Compare integer, string or compile constants with ==, of same class
  • Each case clause can either be empty or end with a keyword (break, continue, throw, return
  • default
  • Use continue and label to fallback
    dart
    switch() {
      case 1:
        executeSomething();
        continue myLabel;
      myLabel:
      case 2:
        executeSomething();
        break;
      default:
        break;
    }
  • A case clause has its local variables

Exceptions

Throw

  • All non-null object can be throwed
  • Usually throw Exception or Error

Catch

dart
try {
    executeSomething();
} on ExceptionType catch (e) {
    print(e);
} on AnotherType {
    print("Exception AnotherType");
} catch (e, s) {
    print("Exception $e, stack trace: $s");
}

Use rethrow to allow exception to propagate

Finally

try {} finally {}Run no matter an exception occurs.

Classes

dart
class Point {
  int x = 0;
  int y = 0;
}

Using class members

dart
int? a = 1;
Point? p;
a = p?.x;
assert(a == null);

Constructors

  • Use constructors
    dart
    var p = Point();
    // Or
    var p2 = new Point();
    // Constant constructors
    var p3 = const ImmutablePoint(0, 1);
    const p4 = ImmutablePoint(0, 1);
    var p5 = ImmutablePoint(0, 1);
    // Constants share the same instance
    assert(identical(p3, p4));
    assert(!identical(p4, p5));
  • Define constructors
    • Generative constructor
      dart
      class Point {
        double x = 0;
        double y = 0;
      
        Point(double x, double y) {
          this.x = x;
          this.y = y;
        }
      }
    • Syntax sugar for assigning arguments to instance variables
      dart
      class Point {
        double x;
        double y;
        // Note that the assignment is before constructor body runs,
        // so x and y can be uninitialized when declaring;
        Point(this.x, this.y);
      }
    • Default constructor
      No argument and invokes the no-argument constructor in the super class.
    • Constructors are not inherited
    • Initializer list
      Initialize instance variables before constructor body runs. Might be useful to initialize final instance variables.
      The right side of initialiers doesn't have access to this.
      dart
      class Point {
        final double x;
        final double y;
      
        Point(double x, double y)
            : x = x,
              y = y {
          print('Created new point.');
        }
      }
    • Invoking a non-default superclass constructor
      dart
      Point(String data)
          : super.someConstructor(data) {
        print('Created');
      }
    • Named constructor
      dart
      Point.origin()
          : x = 0,
            y = 0;
    • Redirecting constructor
      dart
      class Point {
        double x, y;
      
        Point(this.x, this.y);
      
        Point.onXAxis(double x) : this(x, 0);
      }
    • Constant constructors
      • All instance variables must be final
      • Use const before constructors
      • Constant constructors cannot have body
      • Example:
        dart
        class ImmutablePoint {
          final double x, y;
          const ImmutablePoint(this.x, this.y);
        }
    • Factory constructors
      Use factory keyword for constructors that don't always create a new instance.

TODO

Generics, TODO

TODO