官网地址:https://dart.dev/guides/language/language-tour
中文网地址:http://dart.goodev.org/guides/language/language-tour#comments
由于官网上的内容是最新的,中文网上无法即时更新文档,所以这里摘录一下和Java或者Kotlin不同的地方。
Final and const
如果你以后不打算修改一个变量,使用 final 或者 const。 一个 final 变量只能赋值一次;一个 const 变量是编译时常量。 (Const 变量同时也是 final 变量。) 顶级的 final 变量或者类中的 final 变量在 第一次使用的时候初始化。
⚠️注意:实例变量可以是final的,但不能是const的,
final name = "CYC";
final String name = 'CYC'
const 变量为编译时常量。 如果 const 变量在类中,请定义为 static const。 可以直接定义 const 和其值,也 可以定义一个 const 变量使用其他 const 变量的值来初始化其值。
?️这里使用final和使用const的区别是什么呢?
一些场景中,const不用多次冗余来声明
如:
const baz = []; // Equivalent to `const []`
//应该使用:
const primaryColors = [
Color("red", [255, 0, 0]),
Color("green", [0, 255, 0]),
Color("blue", [0, 0, 255]),
];
//冗余的使用
const primaryColors = const [
const Color("red", const [255, 0, 0]),
const Color("green", const [0, 255, 0]),
const Color("blue", const [0, 0, 255]),
];
Number类型
从Dart2.1开始,支持数值类型的自动转型,
double z = 1; // Equivalent to double z = 1.0.
Collection
List
Dart中的list就是数组,使用如下:
var list = [1, 2, 3];//Dart的类型推断出list类型为List<int>
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
创建一个编译时list常量,直接在数组字面量前面加上const ,
var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error.
Dart 2.3 开始在Set,List,Map中引入spread operator (…) 和 null-aware spread operator (…?),使得在向一个Collection集合中插入元素时更加方便,如:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
Dart 2.3 开始引入collection if 和 collection for,在创建Collection时,可以使用条件if和循环for来构建,如:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
Set
可以使用以下两种方式创建一个set,
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
⚠️注意: 如果没有在{ }前面加上范型类型或者变量没有指定类型,那么直接使用{ }默认是创建了一个类型为Map<dynamic, dynamic>的Map。
创建一个编译时常量set,可以在set字面量之前加上const, 如:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.
Map
创建map的方式,同Set,
//直接使用Map字面量声明
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
//使用Map的构造函数
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
#Functions
单函数表达式使用“ =>”
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
可以使用[ ] 表示可选的参数,函数参数默认值可以使用“=”表示,
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold will be true; hidden will be false.
enableFlags(bold: true);
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
函数也是一种类型,可以作为参数和返回值,可以把一个函数赋值给一个变量
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
//返回一个函数类型
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
匿名方法,有时候也被成为lambda或者闭包 closure,如果函数体就只有一个语句,可以使用“=>”简化
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
#Operators
a = value; // 给 a 变量赋值
b ??= value; // 如果 b 是 null,则赋值给 b;
// 如果不是 null,则 b 的值保持不变
Conditional expressions(条件表达式)
Dart 有两个特殊的操作符可以用来替代 if-else 语句:
condition ? expr1 : expr2
如果 condition 是 true,执行 expr1 (并返回执行的结果); 否则执行 expr2 并返回其结果。
expr1 ?? expr2
如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果。
对于实现 Iterable 接口对象上,可以使用以下简化的形式:
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
candidates.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
构造函数
由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作
class Point {
num x;
num y;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
Initializer list(初始化列表)
在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。 使用逗号分隔初始化表达式。
可以使用重定向的构造函数,直接引用主构造函数
class Point {
num x;
num y;
Point(this.x, this.y);
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
//重定向的构造函数,不能有自己的方法体
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
关于常量构造函数和工厂构造函数的介绍:
如果你的类提供一个状态不变的对象,你可以把这些对象 定义为编译时常量。要实现这个功能,需要定义一个 const 构造函数, 并且声明所有类的变量为 final。
class ImmutablePoint {
final num x;
final num y;
const ImmutablePoint(this.x, this.y);
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
}
如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。例如,一个工厂构造函数 可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例。
下面代码演示工厂构造函数 如何从缓存中返回对象。
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to the _ in front
// of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) {
print(msg);
}
}
}
//使用 new 关键字来调用工厂构造函数。
var logger = new Logger('UI');
logger.log('Button clicked');
Method
Dart可以使用set 和get 来定义新的属性,如下:
class Rectangle {
num left;
num top;
num width;
num height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
main() {
var rect = new Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
操作符重载
Dart使用operator关键字 跟上要重载的操作符来定义重载方法:
class Vector {
final int x;
final int y;
const Vector(this.x, this.y);
/// Overrides + (a + b).
Vector operator +(Vector v) {
return new Vector(x + v.x, y + v.y);
}
/// Overrides - (a - b).
Vector operator -(Vector v) {
return new Vector(x - v.x, y - v.y);
}
}
main() {
final v = new Vector(2, 3);
final w = new Vector(2, 2);
// v == (2, 3)
assert(v.x == 2 && v.y == 3);
// v + w == (4, 5)
assert((v + w).x == 4 && (v + w).y == 5);
// v - w == (0, 1)
assert((v - w).x == 0 && (v - w).y == 1);
}
⚠️注意:Dart中的类可以有抽象函数,而不必定义为abstract class抽象类,并且可以实例化。
⚠️注意:Dart中的每个类(枚举类型除外)都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。
实现一个隐式接口使用implements
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Imposter implements Person {
// We have to define this, but we don't use it.
final _name = "";
String greet(who) => 'Hi $who. Do you know who I am?';
}
greetBob(Person person) => person.greet('bob');
main() {
print(greetBob(new Person('kathy')));
print(greetBob(new Imposter()));
}