包含最重要概念、功能、方法等的 Dart 备忘单。初学者的完整快速参考
完整教程请参阅 Dart 中文社区 https://dart.cn/get-dart/
C:\> choco install dart-sdk # Windows
执行以下一次性设置
$ sudo apt-get update$ sudo apt-get install apt-transport-https$ wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg$ echo 'deb [signed-by=/usr/share/keyrings/dart.gpg arch=amd64] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
安装 Dart SDK
$ sudo apt-get update$ sudo apt-get install dart
$ brew tap dart-lang/dart$ brew install dart
// 应用执行开始的顶级函数void main() {print("Hello World!"); // 打印到控制台}
每个应用程序都有一个 main()
函数
$ dart compile exe hellow.dart$ time ./hello.exeHello World!
int x = 2; // 显式键入var p = 5; // 类型推断 - 具有类型推断的通用vardynamic z = 8; // 变量可以采用任何类型z = "cool"; // cool// 如果您从不打算更改变量,请使用 final 或 const// 像这样的东西:final email = "temid@gmail.com";// 与 var 相同,但不能重新分配final String email = "temid@gmail.com";// 你不能改变价值const qty = 5; // 编译时常数
// 整数,范围 -2^63 到 2^63 - 1int age = 20;// 浮点数字double height = 1.85;// 您还可以将变量声明为 num// x 可以同时具有 int 和 double 值num x = 1;x += 2.5;print(x); // 打印: 3.5String name = "Nicola";bool isFavourite = true;bool isLoaded = false;
// 这是一条正常的单行注释/// 这是一个文档注释,用于文档库,/// 类及其成员。 IDE 和 dartdoc 等工具/// doc 特别注释。/* 也支持此类注释 */
// 可以对字符串类型使用单引号或双引号var firstName = 'Nicola';var lastName = "Tesla";// 可以用 $ 将变量嵌入到字符串中String fullName = "$firstName $lastName";// 与 + 连接var name = "Albert " + "Einstein";String upperCase = '${firstName.toUpperCase()}';print(upperCase); // 打印: NICOLA
// 导入核心库import 'dart:math';// 从外部包导入库import 'package:test/test.dart';// 导入文件import 'path/to/my_other_file.dart';// 指定前缀import 'package:lib/lib.dart' as lib;lib.Element element = lib.Element();// 仅导入 fooimport 'package:lib1/lib1.dart' show foo;// 不导入 fooimport 'package:lib2/lib2.dart' hide foo;// 延迟导入,仅在需要时导入import 'package:greetings/hello.dart' deferred as hello;
print(2 + 3); // 打印: 5print(2 - 3); // 打印: -1print(2 * 3); // 打印: 6print(5 / 2); // 打印: 2.5 - 结果是 doubleprint(5 ~/ 2); // 打印: 2 - 结果是n intprint(5 % 2); // 打印: 1 - 余int a = 1, b;
// 增b = ++a; // 前增量 - 在 b 获得其值之前增加 ab = a++; // 后增量 - 在 b 获得它的值之后增加 a// 递b = --a; // 前减量 - 在 b 获得它的值之前减少 ab = a--; // 后减量 - 在 b 获得它的值之后递减 a
// !expr 反转表达式(将 false 更改为 true,反之亦然)// || 逻辑或// && 逻辑与bool isOutOfStock = false;int quantity = 3;if (!isOutOfStock && (quantity == 2 || quantity == 3)) {// ...Order the product...}
print(2 == 2); // 打印: true - 平等的print(2 != 3); // 打印: true - 不相等print(3 > 2); // 打印: true - 比...更棒print(2 < 3); // 打印: true - 少于print(3 >= 3); // 打印: true - 大于或等于print(2 <= 3); // 打印: true - 小于或等于
// 括号可以提高可读性。if ((n % i == 0) && (d % i == 0)) ...// 虽然难以阅读,但等效。if (n % i == 0 && d % i == 0) ...
操作符 | 含义 |
---|---|
& | 与(AND) |
| | 或(OR) |
^ | 异或(XOR) |
~expr | 一元位补码 (0 变为 1;1 变为 0) |
<< | 左移 |
>> | 右移 |
>>> | 无符号右移 |
final value = 0x22;final bitmask = 0x0f;// 与(AND)assert((value & bitmask) == 0x02);// 非与(AND NOT)assert((value & ~bitmask) == 0x20);// 或(OR)assert((value | bitmask) == 0x2f);// 异或(XOR)assert((value ^ bitmask) == 0x2d);assert((value << 4) == 0x220); // 左移assert((value >> 4) == 0x02); // 右移
级联 (.., ?..) 允许您对同一对象进行一系列操作。除了访问实例成员之外,您还可以调用同一对象的实例方法。这通常可以节省您创建临时变量的步骤,并允许您编写更流畅的代码。考虑以下代码:
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;
以 ?...
开头可确保不会对该空对象进行任何级联操作。
querySelector('#confirm') // 获取一个对象?..text = 'Confirm' // 使用它的成员..classes.add('important')..onClick.listen((e) => {window.alert('Confirmed!')})..scrollIntoView();
if(age < 18){print("Teen");} else if( age > 18 && age <60){print("Adult");} else {print("Old");}
enum Pet {dog, cat}Pet myPet = Pet.dog;switch(myPet) {case Pet.dog:print('My Pet is Dog.');break;case Pet.cat:print('My Pet is Cat.');break;default:print('I don\'t have a Pet');}// 打印: My Pet is Dog.
int age = 20;String message = age >= 18 ? "成人" : "儿童";print("年龄类别: $message");// 输出: 年龄类别: 成人
int x = 10;int y = 5;int result = x > y ? x : y > 0 ? y : 0;print("Result: $result");// 输出: Result: 10
while (!dreamsAchieved) {workHard();}
循环迭代之前的 while
循环检查条件
do {workHard();} while (!dreamsAchieved);
do-while
循环在执行循环内的语句后验证条件
for(int i=0; i< 10; i++){print(i);}var numbers = [1,2,3];// 列表的 for-in 循环for(var number in numbers){print(number);}
// 有序的对象组var list = [1, 2, 3];print(list.length); //Print: 3print(list[1]); //Print: 2// 列表声明和初始化的其他方式List<String> cities = <String>["New York", "Mumbai", "Tokyo"];// 创建一个编译时常量的列表const constantCities = const ["New York", "Mumbai", "Tokyo"];
// 映射是关联键和值的对象var person = Map<String, String>();// 要初始化映射,请执行以下操作:person['firstName'] = 'Nicola';person['lastName'] = 'Tesla';print(person);// 打印: {firstName:Nicola, lastName:Tesla}print(person['lastName']);// 打印: Teslavar nobleGases = {// Key: Value2: 'helium',10: 'neon',18: 'argon',};
// Dart 中的集合是唯一项的无序集合var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};// 创建一个空集var names = <String>{};Set<String> names = {}; // 这也有效//var names = {}; // 创建映射,而不是集合
// dart 中的函数是对象并且有一个类型int add(int a, int b){return a+b;}// 函数可以分配给变量int sum = add(2,3); // 回报:5// 可以作为参数传递给其他函数int totalSum = add(2, add(2,3)); // 返回:7
// 只包含一个表达式的函数,您可以使用简写语法bool isFav(Product product) => favProductsList.contains(product);
// 没有名字的小单行函数int add(a,b) => a+b;// lambda 函数大多作为参数传递给其他函数const list = ['apples', 'bananas', 'oranges'];list.forEach((item) =>print('${list.indexOf(item)}: $item'));// 打印: 0: apples 1: bananas 2: oranges
//extension 定义扩展名称 on 扩展类extension StringExtension on String {//扩展方法String capitalize() {if (isEmpty) {return this;}// 将字符串的首字母大写String topStr = this[0].toUpperCase();return '${topStr}${substring(1)}';}}void main(List<String> args) {print("apple".capitalize());// Print: Appleprint("苹果apple".capitalize());// Print: 苹果apple}
在不修改 String 类的前提下为其新增了 capitalize 方法
class Money {final num amount;Money({required this.amount});}// 利用扩展函数特性extension MoneyOperatorExtension<T> on Money {// operator 重载运算符Money operator +(Money elements) {Money newMoney = Money(amount: this.amount + elements.amount);return newMoney;}}void main(List<String> args) {// 怎么样?两个类加起来了Money appleMoney = Money(amount: 10.0);Money cardMoney = Money(amount: 6.0);Money allMoney = cardMoney + appleMoney;print(allMoney.amount);//Print: 16.0}
class Cat {String name;// 方法void voice(){print("Meow");}}
// 类的实例// 在 myCat 下面是 Cat 类的对象void main(){Cat myCat = Cat();myCat.name = "Kitty";myCat.voice(); // 打印: Meow}
class Cat {String name;Cat(this.name);}void main(){Cat myCat = Cat("Kitty");print(myCat.name); // 打印: Kitty}
// 抽象类——不能实例化的类// 这个类被声明为抽象的,因此不能被实例化abstract class AbstractContainer {// 定义构造函数、字段、方法...void updateChildren(); // 抽象方法}
// 提供对对象属性的读写访问class Cat {String name;// getterString get catName {return name;}// settervoid set catName(String name){this.name = name;}}
// 一个人。隐式接口包含 greet()。class Person {// 在接口中,但仅在此库中可见。final String _name;// 不在接口中,因为这是一个构造函数。Person(this._name);// 在接口中String greet(String who) => 'Hello, $who. I am $_name.';}// Person 接口的实现。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')));// 打印: Hello, Bob. I am Kathy.print(greetBob(Impostor()));// 打印: Hi Bob. Do you know who I am?}
class Phone {void use(){_call();_sendMessage();}}// 使用 extends 创建子类class SmartPhone extends Phone {void use(){// 使用 super 来引用超类super.use();_takePhotos();_playGames();}}
enum Color { red, green, blue }
使用枚举,像访问任何其他静态变量一样访问枚举值:
final favoriteColor = Color.blue;if (favoriteColor == Color.blue) {print('Your favorite color is blue!');}
枚举中的每个值都有一个索引获取器,它返回枚举声明中值从零开始的位置。 例如,第一个值的索引为 0,第二个值的索引为 1
assert(Color.red.index == 0);assert(Color.green.index == 1);assert(Color.blue.index == 2);
要获取所有枚举值的列表,请使用枚举的值常量
List<Color> colors = Color.values;assert(colors[2] == Color.blue);
您可以在 switch 语句中使用枚举,如果您没有处理枚举的所有值,您将收到警告:
var aColor = Color.blue;switch (aColor) {case Color.red:print('Red as roses!');break;case Color.green:print('Green as grass!');break;default: // 没有这个,你会看到一个警告print(aColor); // 'Color.blue'}
如果您需要访问枚举值的名称,例如 Color.blue
中的“blue”,请使用 .name
属性:
print(Color.blue.name); // 'blue'
声明了一个具有多个实例、实例变量、一个 getter
和一个已实现接口的增强型枚举
// 简单定义一个枚举类型enum PlanetType { terrestrial, gas, ice }// 定义一个行星复杂的枚举类型enum Planet {mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);// 定义一个构造函数const Planet({required this.planetType, required this.moons, required this.hasRings});// 声明枚举类型中的变量final PlanetType planetType;final int moons;final bool hasRings;// 实现枚举类型中的get 方法bool get isGiant =>planetType == PlanetType.gas || planetType == PlanetType.ice;}// 使用枚举类型void main(){final yourPlanet = Planet.mercury;if (!yourPlanet.isGiant) {print('Your planet is not a "giant planet".');}}
Dart
中类只能单继承,使用Mixin
可以实现多个继承,复用多个类中代码的方法。
// 定义Mixinmixin Piloted {int astronauts = 1;void describeCrew() {print('Number of astronauts: $astronauts');}}
使用with
关键字并在其后跟上Mixin类
的名字来使用
// 使用with将Piloted混入class PilotedCraft extends Spacecraft with Piloted {// ···}
支持混入多个Mixin,如果出现相同的方法后混入的Mixin会覆盖前面的
class Musician extends Performer with Musical {// ···}// 混入多个Mixinclass Maestro extends Person with Musical, Aggressive, Demented {Maestro(String maestroName) {name = maestroName;canConduct = true;}}
使用关键字on
来指定哪些类可以使用该Mixin,比如有Mixin类MusicalPerformer
,但是MusicalPerformer
只能被Musician
类使用,则可以这样定义MusicalPerformer
:
class Musician {// ...}// 现在MusicalPerformer 只能在 Musican及其子类中使用mixin MusicalPerformer on Musician {// ...}class SingerDancer extends Musician with MusicalPerformer {// ...}
// 抛出 throws 或引发 raises 和异常 exceptionthrow IntegerDivisionByZeroException();// 你也可以抛出任意对象throw "Product out of stock!";
try {int c = 3/0;print(c);} on IntegerDivisionByZeroException {// 一个特定的异常print('Can not divide integer by 0.')} on Exception catch (e) {// 任何其他异常情况print('Unknown exception: $e');} catch (e) {// 没有指定类型,处理所有print('Something really unknown: $e');}
// 确保某些代码无论是否抛出异常都能运行try {cookFood();} catch (e) {print('Error: $e'); // 先处理异常} finally {cleanKitchen(); // 然后清理}
// 异步函数:它们在设置可能耗时的操作后返回// async 和 await 关键字支持异步编程Future<String> login() {String userName="Temidjoy";returnFuture.delayed(Duration(seconds: 4), () => userName);}// 异步main() async {print('Authenticating please wait...');String result = await login();print(result);}
int x; // 任何对象的初始值为 null// ?? 空感知运算符x ??=6; // ??= 赋值运算符,仅当变量当前为 null 时才为其赋值print(x); // 打印: 6x ??=3;print(x); // 打印: 6 - 结果仍然是 6print(null ?? 10); // 打印: 10。如果不为空,则显示左侧的值,否则返回右侧的值
// 条件 ? 条件如果为真 : 条件如果为假bool isAvailable;isAvailable ? orderproduct() : addToFavourite();
userObject?.userName// 上面的代码片段等效于以下代码:(userObject != null) ? userObject.userName : null// 您可以将 ? 的多种用途链接起来。一起在一个表达式中userObject?.userName?.toString()// 如果 userObject 或 userObject.userName 为 null,则前面的代码返回 null 并且从不调用 toString()
// 将多个值插入到集合中var list = [1, 2, 3];var list2 = [0, ...list];print(list2.length); // 打印: 4
定义:enum("enumeration"的缩写)是一种特殊的数据类型,可使变量成为一组预定义的常量。枚举用于定义只能从一小组可能值中选择一个的变量。通过为这些值集提供有意义的名称,枚举有助于提高代码的可读性,减少出错率。
// 定义枚举类型enum TrafficLight {red,yellow,green}// 根据交通灯状态打印消息的函数void printTrafficLightMessage(TrafficLight light) {switch (light) {case TrafficLight.red:print('Stop!');break;case TrafficLight.yellow:print('Get ready...');break;case TrafficLight.green:print('Go!');break;}}void main() {// 枚举类型的示例用法TrafficLight currentLight = TrafficLight.green;// 打印当前交通灯状态的消息printTrafficLightMessage(currentLight);}
// 允许您对同一对象进行一系列操作// 而不是这样做var user = User();user.name = "Nicola";user.email = "nicola@g.c";user.age = 24;// 你可以这样做var user = User()..name = "Nicola"..email = "nicola@g.c"..age = 24;
// token 类型非空,但是不用立即赋值late String token;void main(List<String> args) {/// print(token);/// 字段 "token "尚未初始化/// 在初始化前调用就会报错token = "tokenContent";print(token);}