认识 Dart 程序语言,从官方提供的dart-cheatsheet
掌握该语言的特色
这边的行为与 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
}
类似 JS (ES11) 上的 Optional chaining,用来保护 Object 上的属性存取。
这边以 Getters and Settiers 中的范例为例,因为年龄可为空,因为在取用前需要特别加上(?.)。
int? get age {
return _age?.age;
}
Dart参数传递的方式有两种:位置参数以及命名参数。
这边以 Getters and Settiers 中的范例为例:
因为年龄可为空,可选位置参数放在方法参数的最後并使用中刮号[]
包起来。
class User {
String name;
Age? _age;
User(this.name, [int? age]) {
if (age != null) {
this._age = Age(age);
}
}
...
}
我们改写一下上面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
}
注意:一个方法不能同时使用可选位置参数和可选命名参数。
对於例於处理,我们可以使用 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!!!");
}
}
在建构方法上有提供不同类型的建构方式,查看下方的范例:
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
让 dart 透过推论的方式导出变数的型别。
如果我们想要宣告一个变数为常数,我们可以使用关键字final
或是const
取代var
修饰其存取行为,这两个的差别如下:
final
的变数只可以被赋值一次,const
的变数指的是编译时的常数,这边指是在编译後,其值将永远不会被改变。
在类别中的实例(instance)变数可以是final
但不可以是const
虽然 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
建构式用来在编译中建立静态常数物件。
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final int x;
final int y;
const ImmutablePoint(this.x, this.y);
}
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语言特性的学习,当然还有许多课程内容包含泛型、同步非同步、核心函式库、第三方套件等需要时间慢慢上手。
昨天之後又做了一些尝试: 用php7.4-apache做一个新的容器,然後用docker-php-e...
前言 了解hoisting、scope chain对於closure的帮助会非常大,因为这三个是环环...
-安德森报告和TCSEC 1972年,James P. Anderson&Co.在着名的Ander...
在 Windows Server 的作业系统上都是预设无防毒软件的,可是没有防毒软件就会让电脑曝露在...
1.window.alert vs. window.confirm (1)window.alert:...