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
    1
    2
    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
    1
    2
    int? a = null;
    List<String?> listOfNullableStrings = ['one', null];
  • use ! to assert non-null
    1
    int c = couldReturnNullButDoesnt()!.abs();
  • late: Tell Dart that a non-null value will be assigned before using the variable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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
    1
    2
    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

1
2
3
4
5
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

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

    Null-aware spread:

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

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

    1
    2
    3
    4
    5
    6
    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.
1
2
3
4
5
6
7
8
9
10
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
    1
    2
    3
    void main() {

    }
  • optional List<String> parameter
    1
    2
    3
    void main(List<String> arguments) {
    print(arguments);
    }

Anonymous function

1
2
3
4
5
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.

1
2
3
4
5
6
7
8
9
10
11
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.

    1
    2
    3
    4
    var paint = Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 5.0;

    is equavalent to:

    1
    2
    3
    4
    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

1
2
3
4
if () {
} else if () {
} else {
}

For loop

  • Standard for loop
    1
    2
    3
    for (var i = 0; i < 5; i++) {

    }
  • Closures
    Closures inside of Dart’s for loops capture the value of the index.
    1
    2
    3
    4
    5
    6
    7
    8
    var callbacks = [];
    for (var i = 0; i < 2; i++) {
    callbacks.add(() => print(i));
    }
    callbacks.forEach((c) => c());
    // This will print
    // 0
    // 1
  • Iterable
    1
    2
    3
    4
    5
    // for-in
    var l = [1, 2, 3];
    for (final n in l) {
    print(n);
    }
    1
    2
    3
    // 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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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

1
2
3
4
5
6
7
8
9
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

1
2
3
4
class Point {
int x = 0;
int y = 0;
}

Using class members

1
2
3
4
int? a = 1;
Point? p;
a = p?.x;
assert(a == null);

Constructors

  • Use constructors
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
      1
      2
      3
      4
      5
      6
      7
      8
      9
      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
      1
      2
      3
      4
      5
      6
      7
      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.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      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
      1
      2
      3
      4
      Point(String data)
      : super.someConstructor(data) {
      print('Created');
      }
    • Named constructor
      1
      2
      3
      Point.origin()
      : x = 0,
      y = 0;
    • Redirecting constructor
      1
      2
      3
      4
      5
      6
      7
      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:
        1
        2
        3
        4
        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