Flutter体验 Day 4-Dart CheatSheet (2)

Dart CheatSheet (2)

认识 Dart 程序语言,从官方提供的dart-cheatsheet掌握该语言的特色

Dart CheatSheet

Getters and Settiers

这边的行为与 JS (ES6) 语法类似,我们直接看范例程序。

class Age {
  int age;
  Age(this.age);

  bool get isComeOfAge {
    return age >= 18;
  }
}

class User {
  String name;
  Age? _age;

  User(this.name, [int? age]) {
    if (age != null) {
      this._age = Age(age);
    }
  }

  int? get age {
    return _age?.age;
  }

  set age(int? value) {
    if (value != null) {
      _age = Age(value);
    }
  }

  bool get isComeOfAge {
    return _age!.isComeOfAge;
  }
}

void main() {
  // age 为可选参数
  var user = User("Leo");
  print(user.age); // null

  user.age = 35;
  print(user.age); // 35
  print(user.isComeOfAge); // true
}

条件属性存取 (Conditional property access)

类似 JS (ES11) 上的 Optional chaining,用来保护 Object 上的属性存取。

这边以 Getters and Settiers 中的范例为例,因为年龄可为空,因为在取用前需要特别加上(?.)。

  int? get age {
    return _age?.age;
  }

可选位置参数 (Optional positional parameters)

Dart参数传递的方式有两种:位置参数以及命名参数。

这边以 Getters and Settiers 中的范例为例:

因为年龄可为空,可选位置参数放在方法参数的最後并使用中刮号[]包起来。

class User {
  String name;
  Age? _age;

  User(this.name, [int? age]) {
    if (age != null) {
      this._age = Age(age);
    }
  }
  ...
}

可选命名参数 (Optional named parameters)

我们改写一下上面User类别的建构式方法,因为年龄可为空,可选命名参数使用大刮号{}包起来。

在 Flutter 控件的原始码,语法大多是以可选命名参数进行设计,当可选参数较多时这种命名参数的可读性很高。

class User {
  String name;
  Age? _age;

  User(this.name, {Age? age}) {
    if (age != null) {
      this._age = age;
    }
  }
...
}

void main() {
  var user = User("Leo", age: 35);
  print(user.age); // 35
}

注意:一个方法不能同时使用可选位置参数和可选命名参数。

例外处理 (Exceptions)

对於例於处理,我们可以使用 try..catch 的方式补获可能的例外状况,而不影响到主程序的运行,与 JS 不同的地方在於 dart 可指定多个 catch 语句。请参考下列范例:

class CustomException implements Exception {
  String cause;
  CustomException(this.cause);
}

class LogicalException implements Exception {
  String _cause = "打我啊笨蛋";

  toString() {
    return "LogicalException: $_cause";
  }
}

somethingWillThrowError(type) {
  switch (type) {
    case 0:
      throw CustomException("Sing Hosanna");
    case 1:
      throw LogicalException();
    default:
      throw "Unknown Error";
  }
}

void test() {
  try {
    somethingWillThrowError(DateTime.now().microsecondsSinceEpoch % 3);
  } on CustomException {
    print("? He's got the whole world in His hands~");
  } on Exception catch (e) {
    // 取得Exception类型的错误
    print('Exception: ${e}');
    rethrow;
  } catch (e) {
    // 取得未知类型的错误
    print("$e");
  }
}

void main() {
  try {
    test();
  } on LogicalException catch (e) {
    print(e.runtimeType); // LogicalException
    print(e.toString());
  } finally {
    print("I Got You!!!");
  }
}

类别 (Class)

在建构方法上有提供不同类型的建构方式,查看下方的范例:

enum JOB { NEW, FIGHTER, WARRIOR }

class Fighter extends Player {
  final JOB _job = JOB.FIGHTER;
  Fighter(name) : super(name: name);
}

class Warrior extends Player {
  final JOB _job = JOB.WARRIOR;
  Warrior(name) : super(name: name);
}

class Player {
  String name;

  JOB _job;

  // 在建构式中使用 this,可以用来对应类别的属性
  Player({required this.name}) : _job = JOB.NEW;

  // 在建构式函式执行可使用 (:) 进行初始化的动作
  Player.fighter({required this.name}) : _job = JOB.FIGHTER {
    print("Build: Player.fighter [$job]");
  }

  // 可以定义不同建构方法
  Player.fromFighter(String name) : this.fighter(name: name);

  // 工厂方式,使用 factory 宣告让方式会返回 子类别 或是 null
  factory Player.fromJson(Map<String, String> json) {
    var name = json['name']!;
    var job = json['job']!;
    if (job == 'fighter') return Fighter(name);
    if (job == 'warrior') return Warrior(name);

    throw ArgumentError('Unrecognized $job');
  }

  get job {
    return this._job;
  }

  toSring() {
    return "$name $job";
  }
}

void main() {
  var newPlayer = Player(name: "新手");
  print(newPlayer.toSring());

  // 此类别重新转达其他的建构方法 (这边范例实作命名参数转成位置参数的建构方法)
  var fighter = Player.fromFighter("战士");
  print(fighter.toSring());

  var warrior = Player.fromJson({"name": "斗士", "job": "warrior"});
  print(warrior.toSring());
}

var、const、final

在之前的范例中,我们大部份都是使用var让 dart 透过推论的方式导出变数的型别。

如果我们想要宣告一个变数为常数,我们可以使用关键字final或是const取代var修饰其存取行为,这两个的差别如下:

  1. final的变数只可以被赋值一次,const的变数指的是编译时的常数,这边指是在编译後,其值将永远不会被改变。

  2. 在类别中的实例(instance)变数可以是final但不可以是const

  3. 虽然 final 的 object 无法被修改,但是其属性是可以被改变的;相对的 const 的 object 其属性是 immutable 的喔。

class Area {
  String city = "";
  Area(this.city);
}

class User {
  final String name; // 2. 不可为 const
  final Area area;

  User(this.name, this.area);

  // 3. 使用 const 需加上 static 表示有静态常数
  static const value = 999;
}

void main() {
  final aFinalStr = "hi";
  // aFinalStr = "cc";  // 1. 不可修改
  print(aFinalStr);

  const bConstStr = "hello";
  // bConstStr = "cc";  // 1. 不可修改
  print(bConstStr);

  var user = User("Leo", Area("Taiwan"));
  // user.name = "cc"; // 1. 不可修改
  print(user.name);
  print(user.area.city);
  user.area.city = "Taipei";
  // user.area = Area("Tainan"); // 3. 不可修改
  print(user.area.city); // 3. 被异动了

  print(User.value);
}

const建构方式 (Const constructors)

这边我直接引用官网上的范例,概念与上述类别的静态常数是一样的,当你定义的对象永远不会改变时,可以宣告一个 const 建构式用来在编译中建立静态常数物件。

class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);

  final int x;
  final int y;

  const ImmutablePoint(this.x, this.y);
}

mixins

Mixin是一种在多重继承中复用方法的模式,使用关键字 with 将 Mixin 类别中方法混入至想要复用其方法的类别上。

P.S. Mixin没有收录在速查表上,不过其语法的特殊性,我觉得还是需要特别提一下。因为在之後的 Flutter SDK 内的 runApp 函数里有一个类别 WidgetsFlutterBinding 就应用到多个Binding的mixin模式,而建构出 Flutter 运行的底层架构。这边我们先从下列简单的范例认识一下 mixin 的使用方法。

mixin Hello {
  late String name;
  void say() {
    print("Hi, $name !!!");
  }
}

class User with Hello {
  String name;
  User(this.name);
}

void main() {
  var user = User("Leo");
  user.say(); // Hi, Leo !!!
}

课程练习

麻烦至官方速查表中,完成今日学习的章节里的代码范列,连结在这

小结

练习成果

今日完成速查表中列出的dart语言特性的学习,当然还有许多课程内容包含泛型、同步非同步、核心函式库、第三方套件等需要时间慢慢上手。


<<:  使用 XmlPullParser (二)

>>:  Ruby on Rails 模组(Module)

[DAY10]制作容器(九)

昨天之後又做了一些尝试: 用php7.4-apache做一个新的容器,然後用docker-php-e...

Day09-Closure

前言 了解hoisting、scope chain对於closure的帮助会非常大,因为这三个是环环...

参考监视器的非必需属性-高凝聚力(High cohesion)

-安德森报告和TCSEC 1972年,James P. Anderson&Co.在着名的Ander...

Windows Server 2012 R2 安装微软免费防毒软件 Microsoft Security Essentials

在 Windows Server 的作业系统上都是预设无防毒软件的,可是没有防毒软件就会让电脑曝露在...

Day 24 (Js)

1.window.alert vs. window.confirm (1)window.alert:...