变量
var name = 'Bob';
Object name = 'Bob';
late String name;
final name = 'Bob';
final String nickname = 'Bobby';
const bar = 1000000;
const double atm = 1.01325 * bar;
在 Dart 中,未初始化的变量拥有一个默认的初始化值:null
所有的变量都是对象的实例,包括整型
内置类型
1. Number
int a = 1;
double b = 1.1;
2. Strings
var s1 = '使用单引号创建字符串字面量。';
var s2 = "双引号也可以用于创建字符串字面量。";
var s3 = '使用单引号创建字符串时可以使用斜杠来转义那些与单引号冲突的字符串:\'。';
var s4 = "而在双引号中则不需要使用转义与单引号冲突的字符串:'";
// 字符串插值
var s = 'string interpolation,${S2+S3}';
// 多行字符串
var s5 = '''
你可以像这样创建多行字符串。
''';
var s6 = """这也是一个多行字符串。""";
// 原始值
var s = r'在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。';
3. Booleans
bool a = true;
4. Lists
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
// 不可变数组
var constantList = const [1, 2, 3];
// 扩展操作符
var list2 = [0, ...list];
assert(list2.length == 4);
// 如果扩展操作符右边可能为 null ,使用 ...? 来避免产生异常
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
// 集合中使用条件语句
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
// 集合中使用 for
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
5. Sets
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = {};
6. Maps
Map 是用来关联 keys 和 values 的对象。其中键和值都可以是任何类型的对象。
var gifts = {
// 键: 值
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
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';
// 如果检索的 Key 不存在于 Map 中则会返回一个 null
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
函数
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
函数可以有两种形式的参数:必要参数 和 可选参数。必要参数定义在参数列表前面,可选参数则定义在必要参数后面。可选参数可以是 命名的 或 位置的。
// 命名参数默认为可选参数,除非他们被特别标记为 required。
// 当你调用函数时,可以使用 参数名: 参数值 的形式来指定命名参数。例如:
void enableFlags({bool? bold, bool? hidden}) {...}
enableFlags(bold: true, hidden: false);
// 位置参数
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 默认参数
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 的值将为 true;而 hidden 将为 false。
enableFlags(bold: true);
匿名函数
([[类型] 参数[, …]]) {
函数体;
};
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
运算符
~/:除并取整
as:类型转换
is:如果对象是指定类型则返回 true
is!:如果对象是指定类型则返回 false
??=:(b ??= value; 只有 b 为 null 的时候才会赋值)
expr1 ?? expr2:如果expr1 为非 null 则返回其值,否则执行expr2 并返回其值
级联运算符 (.., ?..) 可以让你在同一个对象上连续调用多个对象的变量或方法,比如:
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = '[email protected]'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
?.:类成员访问(b?.data->b不为null的时候访问data成员)
流程控制
1. if-else
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
2. for
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
for (var candidate in candidates) {
candidate.interview();
}
3. while/do-while
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
4. Break 和 Continue
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
5. Switch 和 Case
var command = 'CLOSED';
switch (command) {
case 'CLOSED': // case 语句为空时的 fall-through 形式。
case 'NOW_CLOSED':
// case 条件值为 CLOSED 和 NOW_CLOSED 时均会执行该语句。
executeNowClosed();
break;
default:
executeUnknown();
}
6. 异常
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // 先处理异常。
} finally {
cleanLlamaStalls(); // 然后清理。
}
类
- 构造函数
class Point {
double? x; // Declare instance variable x, initially null.
double? y; // Declare y, initially null.
double z = 0; // Declare z, initially 0.
final double distanceFromOrigin;
// 1. 普通构造函数
Point(double x, double y) : super.fromJson(data) {
this.x = x;
this.y = y;
}
// 2. 构造函数语法糖
Point(this.x, this.y);
// 3. 命名式构造函数
Point.origin()
: x = xOrigin,
y = yOrigin;
// 4. 初始化列表
Point(double x, double y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
// 5. 委托实现给主构造函数。
Point.alongXAxis(double x) : this(x, 0);
}
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
var a = p?.y; // p 不为 null 时访问 y 变量
- 常量构造函数
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
// 所有变量都是 final
final double x, y;
// const 关键字描述构造函数
const ImmutablePoint(this.x, this.y);
}
- 工厂构造函数
构造函数前加 factory 关键字,工厂构造函数并非总是会返回新的实例对象,在工厂构造函数中无法访问 this。
class Logger {
final String name;
bool mute = false;
// _cache 变量是库私有的,因为在其名字前面有下划线。
static final Map _cache =
{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
factory Logger.fromJson(Map json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
- 实例方法
class Point {
double x = 0;
double y = 0;
double left, top, width, height;
Point(this.x, this.y);
// 实例方法
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
// 运算符重写
Point operator +(Point v) => Point(x + v.x, y + v.y);
Point operator -(Point v) => Point(x - v.x, y - v.y);
// Getter && Setter
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
- 抽象类&&抽象方法
抽象方法只能存在于抽象类中,抽象类无法被实例化
abstract class Doer {
// 定义实例变量和方法等等……
void doSomething(); // 定义一个抽象方法。
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供一个实现,所以在这里该方法不再是抽象的……
}
}
- 隐式接口
class Person {
// _name 变量同样包含在接口中,但它只是库内可见的。
final _name;
// 构造函数不在接口中。
Person(this._name);
// greet() 方法在接口中。
String greet(String who) => '你好,$who。我是$_name。';
}
// Person 接口的一个实现。
class Impostor implements Person, Location {
get _name => '';
String greet(String who) => '你好$who。你知道我是谁吗?';
}
String greetBob(Person person) => person.greet('小芳');
void main() {
print(greetBob(Person('小芸')));
print(greetBob(Impostor()));
}
- 类扩展
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
}
class SmartTelevision extends Television {
@override // @override 注解表示重写了父类方法
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// 除非你重写 noSuchMethod,否则调用一个不存在的成员会导致 NoSuchMethodError。
@override
void noSuchMethod(Invocation invocation) {
print('你尝试使用一个不存在的成员:' +
'${invocation.memberName}');
}
}
- 枚举类型
enum Color { red, green, blue }
// 每一个枚举值都有一个名为 index 成员变量的 Getter 方法,该方法将会返回以 0 为基准索引的位置值
assert(Color.red.index == 0);
assert(Color.green.index == 1);
// 获取所有枚举值
List colors = Color.values;
assert(colors[2] == Color.blue);
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('红如玫瑰!');
break;
case Color.green:
print('绿如草原!');
break;
default: // 没有该语句会出现警告。
print(aColor); // 'Color.blue'
}
- 使用 Mixin
Mixin 是一种在多重继承中复用某个类中代码的方法模式,可以认为是带实现的接口
class Musician extends Performer with Musical {
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
// 自定义Mixin
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
// 可以使用关键字 on 来指定哪些类可以使用该 Mixin 类,比如有 Mixin 类 A,但是 A 只能被 B 类使用,则可以这样定义 A:
class Musician {}
mixin MusicalPerformer on Musician {}
class SingerDancer extends Musician with MusicalPerformer {}
- 类变量和方法
class Point {
static const initialCapacity = 16;
double x, y;
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
assert(Queue.initialCapacity == 16);
}
- 泛型
var names = ['小芸', '小芳', '小民'];
var uniqueNames = {'小芸', '小芳', '小民'};
var pages = {
'index.html': '主页',
'robots.txt': '网页机器人提示',
'humans.txt': '我们是人类,不是机器'
};
var nameSet = Set.from(names);
// 限制泛型
class Foo {
// 具体实现……
String toString() => "'Foo<$T>' 的实例";
}
// 范型方法
T first(List ts) {
// 处理一些初始化工作或错误检测……
T tmp = ts[0];
// 处理一些额外的检查……
return tmp;
}
- 使用库
// 内置库
import 'dart:html';
// 其他库
import 'package:test/test.dart';
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// 库冲突管理
// 使用 lib1 的 Element 类。
Element element1 = Element();
// 使用 lib2 的 Element 类。
lib2.Element element2 = lib2.Element();
// 只导入 lib1 中的 foo。(Import only foo).
import 'package:lib1/lib1.dart' show foo;
// 导入 lib2 中除了 foo 外的所有。
import 'package:lib2/lib2.dart' hide foo;
// 延迟加载库
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}