Dart 资源网站
官网:
如果想要在线运行 Dart 代码,可以使用 DartPad
生态:
Dart 语言概览:https://dart.cn/samples
Dart 速查表:https://dart.cn/codelabs/dart-cheatsheet
环境搭建
Dart 的环境搭建主要有两种方式
-
跟随 Flutter SDK 一起安装(推荐)
从 Flutter 1.21 版本开始,Flutter SDK 会同时包含完整的 Dart SDK。即:如果你已经安装了 Flutter,就无需再下载 Dart SDK 了。
例如,我在 flutter SDK 的 bin 目录下,也找到了 dart.bat -
单独安装 Dart SDK
参考官网文档:https://dart.dev/get-dart
Dart 环境搭建 – 绑定环境变量
Dart 语法基础
注释
-
单行注释
// 单行注释
-
多行注释
/* 多行注释 */
-
文档注释
/// 这是文档注释
可以通过 dartdoc 将注释转成文档 (文档注释支持 markdown 语法)
变量
- 变量是一个引用,根据Dart中万物皆对象原则,即变量存储的都是对象的引用,或者说它们都是指向对象。
- 声明变量
- 明确指定类型:int age = 18;
- 不指定类型:var age = 18; 或 dynamic age = 18;
- 变量名大小写敏感(age 和 Age 是俩个不同的变量)
- 变量默认值是 null
- Dart 变量的值不会进行隐式转换(null 不会自动转成 false)
常量
- 声明常量
- const age = 18;
- final age =18;
- const 与 final 的区别
- const time=DateTime.now(); // 报错-无法将运行时的值分配给const变量
- final time=DateTime.now(); // 成功-可以将运行时的值分配给final变量
Dart 数据类型
- Number
- num
- int
- double
- String
- Boolean
- List
- Set
- Map
- Rune (用于在字符串中表示 Unicode 字符)
- Symbol
Number
- Dart 中的数字由三个关键字描述
- num 是数值类型,既包含整数,也包含浮点数(小数)
- int 整数类型(必须是整数)
- double 浮点数类型(既可以是整数,也可以是小数)
- num 是数值类型,既包含整数,也包含浮点数(小数)
- 常用 API
void main() {
// 声明整数
int count = 3;
print(count);
// 声明浮点数
double price = 3.7;
print(price);
// 声明数值类型
num n1 = 3.7;
print(n1);
// 类型转换
print(n1.toString());
print(3.8.toInt()); // 向下取整
// 四舍五入
print(3.1415926.round());
print(3.1415926.toStringAsFixed(4));
// 返回余数
print(10.remainder(4));
// 数字比较: 0: 相同,1:大于,-1:小于
print(10.compareTo(12));
// 返回最大公约数
print(12.gcd(18));
// 科学计数法
print(1000.toStringAsExponential(1));
}
String
-
声明字符串(String)
- 单引号,双引号都可以
- 三个引号可以声明包括换行符的字符串
-
常见 API
-
正则表达式
- RegExp(r’正则表达式’)
- RegExp(r’\d+’)
void main() {
// 声明字符串
// var str1 = 'Hello, World'; // 单引号
// print(str1);
// var str2 = "你好,世界"; // 双引号
// print(str2);
String str1 = 'Hello, World'; // 单引号
print(str1);
String str2 = "你好,世界"; // 双引号
print(str2);
// 通过三个引号声明字符串
String str3 = '''Hello
World
''';
print(str3);
// 常见操作
// 字符串拼接
print(str1 + str2);
print("$str1 $str2");
// 字符串的分隔
print(str1.split(''));
// 字符串的裁切
print(' abc '.trim());
// 判断字符串是否为空
print(''.isEmpty);
print(''.isNotEmpty);
// 字符串替换
print(str1.replaceAll('World', 'Dart'));
// 支持正则替换
print('h1k2d3n4n5n'.replaceAll(RegExp(r'\d+'), '_'));
// 通过正则匹配手机号
var isPhone = RegExp(r'^1\d{10}$');
print(isPhone.hasMatch('13333333333'));
print(isPhone.hasMatch('1333333333'));
// 查找字符串
print(str1.contains('e'));
// 定位字符串
print(str1.indexOf('e'));
}
Boolean
Dart 的类型安全不允许你使用类似if(nonbooleanValue)或者assert(nonbooleanValue)这样的代码检查布尔值。相反,你应该总是显示地检查布尔值,比如像下面的代码这样:
void main() {
// 声明布尔类型
bool flag1 = true;
print(flag1);
bool flag2 = false;
print(flag2);
// 显式地进行判断
var flag3;
if (flag3 == null) {
print('真');
} else {
print('假');
}
// 一些特殊的判断场景
var n1 = 0 / 0;
print(n1);
print(n1.isNaN);
}
List(列表)
- 在 Dart 中数组由List对象表示。List 有两中声明方式
- 字面量方式 List list = []; // 不设定元素的数据类型
- List list = <int>[]; 限定元素的数据类型为 int
- 构造函数形式
- List list = new List.empty(growable: true); // 不限定长度的空列表
- List list = new List.filled(3, 6); // 声明指定长度的填充列表
- 扩展操作符 (…)
- var list = [1,2,3];
- var list2 = [0,…list] // [0,1,2,3]
- 常用 API:
遍历 List
- forEach()
- 遍历列表
- map()
- 遍历并处理元素,然后生成新的列表
- where()
- 返回满足条件的数据
- any()
- 只要有一项满足条件,即返回 true
- every()
- 判断是否每一项都满足条件,都满足条件才返回 true
Set(集合)
- Set 是一个无序的,元素唯一的集合
- Set 有字面量和构造函数两种声明方式(字面量中用大括号)
- 无法通过下标取值
- 具有集合特有的操作
- 列如:求交集,并集,差集等
- 常用 API:https://api.dart.dev/stable/dart-core/Set-class.html
Map(映射)
- Map 是一个无序的 key-value (键值对)集合,就是大家熟知的字典(dictionary)或者哈希(hash)。
- 声明方式
- var map = { key1: value1, key2: value2 };
- var map = new Map();
- map[‘key’] = value;
- 常用 API:https://api.dart.dev/stable/dart-core/Map-class.html
Dart 运算符
地板除
先进行除法运算,然后向下取证
assert(5 ~/ 2 == 2); // 结果是一个整数
类型判断运算符
避空运算符
??,左侧表达式为空时,返回右边的表达式。
print(1 ?? 3); // 返回 1
print(null ?? 12); // 返回 12
var foo;
// foo = 6;
print(foo ?? 0); // 如果 foo 是 null,则返回 0
??=变量为空时,才为其赋值:
var a;
// if (a == null) {
// a = 3;
// }
a ??= 3;
print(a);
a ??= 6; // 如果 a 不是 null。则赋值失败
print(a);
条件属性访问
要保护可能会为空的属性的正常访问,请在点(.)之前加一个问号(?)。
var m = new Map();
print(m.length);
var obj;
// print(obj.length); // The getter 'length' was called on null.
print(obj?.length);
级联运算符
要对同一对象执行一系列操作,请使用级联(…)。我们都看到过这样的表达式:
// 调用myObject的someMethod方法,返回someMethod的返回值
myObject.someMethod()
//调用myObject的someMethod方法,返回myObject对象的引用
myObject..someMethod()
级联可以让你在同一个对象上连续调用多个对象的变量或方法。例如:
Set s = new Set();
s.add(1);
s.add(2);
s.add(3);
s.remove(2);
print(s);
使用级联:
Set s = new Set();
s..add('a')..add('b')
..add('c')
..remove('b');
print(s);
Dart 函数
声明函数
- Dart 中声明函数,不需要 function 关键字
- 箭头函数
- Dart 中的箭头函数中,函数体只能写一行且不能带有结束的分号
- Dart 中的箭头函数,只是函数的一种简写方式
- 匿名函数
- 立即执行函数
函数参数
- 必填参数
- 参数类型 参数名称
- 可选参数
- 放在必选参数后面
- 通过中括号包裹起来
- 带默认值的可选参数
- 命名参数
- 用大括号包裹起来
- 调用函数时,命名参数的名称与声明函数中的名称保持一致
- 函数参数
void main() {
// 必填参数
String userInfo(String name) {
return '你好:$name';
}
String res = userInfo('张三');
// 可选参数
String userInfo(String name, [int age = 0]) {
return '你好:$name, 年龄:$age';
}
String res = userInfo('张三', 20);
print(res);
// 命名参数
String userInfo(String name, {int age = 0}) {
return '你好:$name, 年龄:$age';
}
// 命名参数调用时,需要与声明时的形参一致
String res = userInfo('张三', age: 20);
print(res);
// 函数参数
var myPrint = (value) {
print(value);
};
List fruits = ['苹果', '香蕉', '猕猴桃'];
// 将匿名函数 myPrint 传递给函数 forEach
fruits.forEach(myPrint);
}
异步函数
- JavaScript 中的异步调用可以通过 Promise 来实现
- async 函数返回一个 Promise。awate 用于等待 Promise
- Dart 中,异步调用通过 Future 来实现
- async 函数返回一个 Future 。awate 用于等待 Future
- Future 详情
对象与类
类
简介
- 类是通过 class 声明的代码段,包括属性和方法。
- 属性:用来描述类的变量
- 方法:类中的函数称为类的方法
- 对象是类的实例化结果 (var obj = new MyClass())
- 编程方式
- 面向对象编程 (OOP)
- 面向过程编程 (POP)
构造器(构造函数)
- 默认构造函数
- 与类同名的函数,在实例化时,自动被调用
- 命名构造函数
- 在类中使用命名构造器实现多个构造器,可以提供额外的清晰度:
- 常量构造函数
- 如果生成类的对象不会变,您可以通过常量构造函数使这些对象成为编译时常量
- 工厂构造函数
- 通过 factory 关键字声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例
class Person { String name; static Person instance; // 工厂构造函数 factory Person([String name = '刘备']) { // 工厂构造函数中,不能使用 this 关键字 // print(this.name); if (Person.instance == null) { // 第一次实例化 Person.instance = new Person.newSelf(name); } // 非第一次实例化 return Person.instance; } // 命名构造函数 Person.newSelf(this.name); } void main() { // 实例化操作 Person p1 = new Person('关羽'); print(p1.name); Person p2 = new Person('张飞'); print(p2.name); print(p1 == p2); }
访问修饰
- Dart 与 TypeScript 不同,没有访问修饰符( public、protected和private)
- Dart 类中,默认的访问修饰符是公开的(即 public)
- 如果属性或方法以下划线 (_) 开头,则表示私有(即 private)
- 只有把类单独抽离出去,私有属性和方法才起作用
getter 与 setter
- Getter(获取器)是通过 get 关键字修饰的方法
- 函数没有小括号,访问时也没有小括号(像访问属性一样访问方法)
- Setter (修改器)是通过 set 关键字修饰的方法
- 访问时像设置属性一样给函数传参
初始化列表
-
初始化列表的作用是,在构造函数中给定属性的默认值
class Rect { int height; int width; // 初始化列表 Rect() : height = 4, width = 20 { print('${this.height} -- ${this.width}'); } } class Point { double x, y, z; Point(this.x, this.y, this.z); // 初始化列表的特殊用法(重定向构造函数) Point.twoD(double x, double y) : this(x, y, 0); }
static
- static 关键字用来指定静态成员
- 通过 static 修饰的属性是静态属性
- 通过 static 修饰的方法是静态方法
- 静态成员可以通过类名称直接访问(不需要实例化)
- 实例化是比较消耗资源的,声明静态成员,可以提高程序性能
- 静态方法不能访问非静态成员,非静态方法可以访问静态成员
- 静态方法中不能使用 this 关键字
- 不能使用 this 关键字访问静态属性
元数据
- 元数据以@开头,可以给代码标记一些额外的信息
- 元数据可以用来库,类,构造器,函数,字段,参数或变量声明的前面
- @override (重写)
- 某方法添加了该注解后,表示重写了父类中的同名方法
- @required (必填)
- 可以通过 @required 来注解 Dart 中的命名参数,用来指示它是必填参数
- @deprecated (弃用)
- 若某类或某方法加上该注解之后,表示此方法或类不再建议使用
继承
- 可以根据先后关系,将类分为父类和子类
- 子类通过 extend 关键字继承父类
- 继承后子类中可以使用父类中可见的内容(属性和方法)
- 子类中可以通过 @overried 元数据来标记 “覆写” 方法
- “覆写”方法:子类中与父类中同名的方法
- 子类中,可以通过 super 关键字来引用父类中,可见的内容
- 属性
- 方法(普通构造函数,命名构造函数)
抽象类
- 抽象类是用 abstract 关键字修饰的类
- 抽象类的作用是充当普通类的模板,约定一些必要的属性和方法
- 抽象方法是指没有方法体的方法
- 抽象类中一般都有抽象方法,也可以没有抽象方法
- 普通类中不能有抽象方法
- 抽象类不能被示列化 (new)
- 抽象类可以被普通类继承 (extend)
- 如果普通类继承抽象类,必须实现抽象类中的所有抽象方法
- 抽象类还可以充当接口被实现 (implements)
- 如果把抽象类当做接口实现的话,普通类必须实现抽象类里面定义的所有属性和方法
接口
- 接口在 Dart 中就是一个类(只是用法不同)
- 与 TypeScript 不同,TypeScript 中的接口需要用 interface 关键字声明;Dart 中不需要
- 接口可以是任意类,但一般使用抽象类做接口
- 一个类可以实现多个接口(implements),多个接口用逗号分隔
- class Phone implements Processor, Camera { … }
- 接口可以看成一个个小零件。类实现接口就相当于组装零件
- 普通类实现接口后,必须重写接口中的所有属性和方法
混入(Mixin)
- 混入(Mixin)是一段公共代码。混入有两种声明方式:
- 将类当作混入 class MixinA { … }
- 作为 Mixin 的类只能继承 Object,不能继承其他类
- 作为 Mixin 的类不能有构造函数
- 使用 mixin 关键字声明 mixin MinxinB { … }
- 将类当作混入 class MixinA { … }
- 混入(Mixin)可以提高代码复用率,普通类可以通过 with 来使用混入
- class Myclass with MicxinA MixinB { … }
- 使用多个混入时,后引入的混入会覆盖之前引入中的重复内容
- MixinA 和 MinxinB 都有 hello() 方法,Myclass 会使用 MixinB 中的
泛型(Generics)
枚举类型
- 枚举数量固定的常量值,通过 enmu 关键字声明
enum Color { red, green, blue} - 枚举的values常量,可以获取所有枚举值列表( list )
List colors = Color.values; - 可以通过 index 获取值的索引
assert(Color.green.index==1);
Dart 库与生态
简介
- Dart 中的库就是具有特定功能的模块
- 可能包含单个文件,也可能包含多个文件
- 按照库的作者进行划分,可以将库分为三类
- 自定义库:(工程师自己写)
- 系统库:(Dart 中自带的)
- 第三方库:(Dart 生态中的)
- Dart 生态
- https://pub.dev
- pub 命令
系统库
- 系统库(也叫核心库)是 Dart 提供的常用内置库
- 不需要单独下载,就可以直接使用
- 引入:
import ‘dart:库名’;- import ‘dart:core’; // 会自动引入 (无需手动引入)
- 系统库列表
- https://dart.cn/guides/libraries
第三方库(包)
- 来源
- 使用
- 在项目根目录下声明 pubspec.yaml 文件
- 在 pubspec.yaml 中声明依赖(第三方包)
- 通过 pub get 命令安装依赖(第三方包)
- 在项目中引入已安装的第三方库(import ‘package:xxxxx/xxxx.dart’;)
- 第三方库的结构
- 一个第三方库,必须包含一个 pubspec.yaml 文件
- pubspec.yaml