A basic Dart program
void printInteger(int aNumber) {
print('The number is $aNumber');
}
void main() {
var nummber = 43;
printInteger(number);
}
// 注释
void : 返回参数, void表示无返回
int : 数据类型
$aNumber : 格式化输出变量 或者 ${aNumber}
main : 主函数, 程序入口
var : 声明变量
Important Concepts
- 一切皆对象, 每个对象都是一个类的实例, 所有的对象都继承自
Object - 尽管Dart是强类型, 但是声明的时候类型是可以省略的, Dart可以
推断类型 - Dart从
2.12开始有Null Safety, 空类型安全, 声明一个变量有可能为null的时候, 可以在类型后面加上?比如:int?, 如果很确定不为空则可以使用! - 如果声明的类型可以是任何对象则可以使用
Object? - Dart支持泛型
List<int> - Dart没有修饰符, 如果想表示私有变量则可以使用
_开头 - Dart支持三目运算符
condition ? expr1 : expr2也支持if-else
内置类型
- Numbers(int, double)
- Strings(String)
- Booleans(bool)
- Lists(List, also know as arrays)
- Sets(Set)
- Map(Map)
- Runes(Runes)
- Symbols(Symbol)
- null(Null)
还有一些比较特殊的类型
- Object: 是所有对象的父类,包括Null
- Enum: 所有enums的父类
- Future&Stream: 在异步中
- Iterable: 遍历
- Never: 表示永远无法执行的语句?
- dynamic: 禁止静态检查?
- void: return type
List中有一个比较好用的, list展开符号 ...
var list = [1, 2, 3];
var list_a = [4, ...list]; // 得到 [4, 1, 2, 3]
如果是非null的时候才展开, 就可以使用...?
var list_b = [5, ...?list];
collection if
var nav = [1, 2, 3, if(true) 4];
collection for
var list_a = [1, 2, 3];
var list_b = [4, for (var i in list_a) i];
Sets跟list比起来就是一个无序集合, 没有下标
var names = <String>{}; // 字符集合
names.add('a');
names.addAll(another sets);
// list支持的操作 ... ...? if for 什么的, set都支持
var names = {}; // 这是一个map不是一个set
Maps 字典
// 类型可以省略
var gifts = Map<String, String>{
"key1": "value1",
"key2": "value2"
};
获取value: gifts["key1"]
甚至可以用数字做key
var gift = {
1: "value1",
2: "value2"
};
获取value: gift[1] // 注意, 这里不需要引号
如果获取一个不存在的, 则会返回null
list 的那些操作 ... ...? if for 也都支持
Runes and grapheme clusters
import 'package:characters/characters.dart';
...
var hi = 'Hi 🇩🇰';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}\n');
Fuctions
Dart是一个面向对象的语言, 即使是functions也有一个类型Function
bool isNoble(int aNumber) {
return true
}
可以简写为
bool isNoble(int aNumber) => false // 也就是所谓的箭头语法
命名参数
// 必须是用大括号
void enableFlags({bool? bold, bool? hidden}) {...}
enableFlags(bold: true, hidden: false);
如果参数不可为空, 那么就设置默认值
void enableFlags({bool? bold = false})
或者
void enableFalgs(bool? bold, [bool? hidden = false])
Lexical scope
Function makeAdder(int addBy) {
return (int i) => addBy + i; // 返回的是 接收int, 然后返回 addBy + 接收过来的参数和
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2); // add2 是一个函数
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5); // 3 + 2
assert(add4(3) == 7);
}
Type test operators
as 类型转换 (employee as Person).firstName = 'Bob';
is 类型判断 if (employee is Person) employee.firstName = 'Bob';
is! True if the object doesn’t have the specified type
b ??= value 如果b为空, 就赋值
Conditional expressions 条件表达式
三目运算符 isTrue ? 'a' : 'b';
expr1 ?? expr2 如果 expr1 non-null 则返回expr1的返回值, 否则 返回expr2的值
Cascade notation 可以操作同一个对象
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
// 这里返回的对象, 不一定存在 所以使用?..
querySelector('#confirm') // Get an object.
?..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();
条件过滤
var list = [1, 23, 4, 5];
list.where((element) => element > 3).forEach((element) {
print(element);
});
Throw 异常 Catch
throw FormatException('Expected at least 1 section');
或者
throw 'out of memory';
try {
} on OutOfLlamasException {
} on Exception catch (e){
} catch (e) {
} finally {
}
Getting an object’s type
var a = [1, 23, 4];
print(a.runtimeType); // List<int>
Instance variables
Class
class Point {
double? x; // default null
double? y;
double z = 0;
// 构造函数
Point(this.x, this.y);
}
类的继承
class Person {
String? firstName;
Person.fromJson(Map data) {
print("in person");
}
}
class Employee extends Person {
// 这里必须调用父类的fromJson
Employee.fromJson(super.data) : super.fromJson() {
print("in employee");
}
}
如果父类有构造方法
class Vector2d {
final double x;
final double y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// 这里需要调用父类, 或者可以这么写
// Vecoor3d(final double x, final double y, this.z) : super(x, y);
Vector3d(super.x, super.y, this.z);
}
如果父类构造方法有 require关键字
class Vector2d {
// ...
Vector2d.named({required this.x, required this.y});
}
class Vector3d extends Vector2d {
// ...
// 把y值传递给父类的构造方法
// Vector3d.yzPlane({required double y, required this.z})
// : super.named(x: 0, y: y);
Vector3d.yzPlane({required super.y, required this.z}) : super.named(x: 0);
}
代理给主构造方法
class Point {
double x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(double x) : this(x, 0);
}
Operators 操作符重写
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
Getters and setters
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
Abstract classes 抽象类 和 接口
abstract class AbstractContainer {
// Define constructors, fields, methods...
void updateChildren(); // Abstract method.
}
//person 类有一个 greet() 方法
class Person {
// In the interface, but visible only in this library.
final String _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// implements 实现一个接口, 可以实现多个 , 分开
class Impostor implements Person {
String get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
Extending a class 继承一个类
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn(); // xi
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
重写属性的话, 需要使用 @override 关键字
@override
set contrast(num value) {...}
重写方法也一样
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: '
'${invocation.memberName}');
}
枚举
enum Color { red, green, blue }
assert(Color.red.index == 0);
print(Color.red.name);
Adding features to a class: mixins
在多重继承中复用某个类中代码的方法模式, 使用with关键字, 后面跟上Mixin类的名字来使用
想要实现Mixin的话, 这个类必须继承自Object, 并且没有构造函数
可以使用on来指定哪些类可以使用该Mixin类
mixin a {}
mixin b {}
class c extends d with a {}
class e extends d with a, b {}
mixin f on x {} // 指定只有x这个类可以 如果有别的类想要mixin f 必须继承自x
Asynchrony support 异步
// 要使用await 必须 函数后面必须使用async
Future<void> checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
await for 是等待一个循环遍历返回
Generators
- Synchronous generator: Returns an
Iterableobject. - Asynchronous generator: Returns a
Streamobject.
Isolates
Dart支持并发: async-await, isolates, 比如: Future和Stream
void main() async {
// Read some data.
final fileData = await _readFileAsync();
final jsonData = jsonDecode(fileData);
// Use that data.
print('Number of JSON keys: ${jsonData.length}');
}
Future<String> _readFileAsync() async {
final file = File(filename);
final contents = await file.readAsString();
return contents.trim();
Isolate的使用
void main() async {
// Read some data.
final jsonData = await _parseInBackground();
// Use that data
print('Number of JSON keys: ${jsonData.length}');
}
// Spawns an isolate and waits for the first message
// 一旦isolate 开始执行, main isolate就会等待结果, 因为ReceivePort 实现了Stream
Future<Map<String, dynamic>> _parseInBackground() async {
final p = ReceivePort(); // 允许isolate 发消息给 main isolate
// spawn 创建并开始一个isolate 在后台工作
// 第一个参数是要执行的任务, 第二个是用来通信的port
await Isolate.spawn(_readAndParseJson, p.sendPort);
return await p.first as Map<String, dynamic>;
}
// 而且这里需要注意, 如果是多次发送数据, 则是请求 --> 然后发送这种模式下进行的
Future<void> _readAndParseJson(SendPort p) async {
final fileData = await File(filename).readAsString();
final jsonData = jsonDecode(fileData);
// 解析完成之后, 退出isolate,
// SendPort.send 发送的是数据的copy, 如果使用Isolate.exit()的话不会copy, 但是会跨Isolate
Isolate.exit(p, jsonData);
}
Typedefs 别名
typedef IntList = List<int>;
IntList il = [1, 2, 3];
typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // Same thing but shorter and clearer.
Metadata 为code提供额外的信息, 比如 过期 deprecated
class Television {
/// Use [turnOn] to turn the power on instead.
@Deprecated('Use turnOn instead')
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {...}
// ···
}
也可以定义自己的metadata
library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}
使用的时候
import 'todo.dart';
@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}