引言
最近flutter发展的如火如荼,而Dart作为flutter的开发语言,了解一下伐?

语言特征
dart 中一切皆对象 dart这个特征和java很像,所有变量、方法都是对象,那怕仅仅是个数字或字符串
入口函数
在dart项目中,必须声明一个入口函数main,这也很java,程序从main函数开始运行(习惯使用js的需要注意这一点)。
void main(){
print('hello dart!')
}
变量声明
- 一般声明变量必须明确类型,类型明确后不能改变,未赋值默认值都是null
int i = 2; i = '3' ; // error:i为int类型,不能赋值字符串类型 - var 可以声明任意类型的变量,赋值后类型不能再改变
var i; i = 2; i = 3; i = '4'; // error: var 变量赋值后,类型不能再改变 - dynamic 可以声明动态类型的变量,每次赋值类型不受限制
dynamic d = 1; d = '123'; // 变量类型确定后还可以再赋值其他类型 - final 变量只能赋值一次,声明时必须初始化
final a = 1; a = 2; // error: final变量只能赋值一次,再次赋值报错 final b = [2]; b[0] = 1; b.add(2); // final 虽然不能再次赋值,但是可以改变他成员变量的值 - const 变量是编译时常量,是一种特殊的final变量
const a = 1; a = 2; // error: const变量只能在初始化时赋值 const b = [2]; b.add(2); // error: const 变量中的成员变量也不可再次改变
方法
- 一般定义方法须明确入参个数、类型及出参的类型
// 方法定义,明确入参和出参,编译时可以做类型校验,提前发现一些错误 int add(int m, int n) { return m + n; } void main() { int a = add(50, 30); String b = add('50', 30); // error: 入参类型和出参类型不正确,编译不通过 } - 如果不明确定义方法入参和出参参数类型,编译时无法进行类型检查
// 出参和入参的类型可以忽略,如果忽略,编译时无法进行类型检查 add( m, n) { return m + n; } void main() { int a = add(50, 30); String b = add('50', 30); // 可以通过编译,但在运行时会报异常 } - 方法入参也可以使用基于命名或位置的可选参数
// 可选位置参数 // 可选参数后面不能再有参数 int add(int m, [int n]) { int sum = m; if (n != null) { sum += n; } return sum; } void main() { print(add(1)); print(add(1, 2)); }// 可选命名参数 int add({int m, int n}) { int sum = 0; if (m != null) { sum += m; } if (n != null) { sum += n; } return sum; } void main() { print(add()); print(add(m: 1)); print(add(n: 2)); print(add(m: 1, n: 2)); } - 定义方法入参时可以定义可选参数的默认值,默认值必须是编译时常量
// 默认参数值 // 默认值只能给可选参数设置 // 位置可选参数匹配顺序是从左到右的,即便有默认参数值 int add(int m, [int n = 0, int i]) { var sum = m + n; if (i != null) { sum += i; } return sum; } void main() { print(add(1)); print(add(1, 2)); } - 箭头函数只能跟一个表达式,不能使用语句和代码块(前端开发人员要特别注意,和js的箭头函数不同)
// => 函数 void main() { var add = (int m, int n) => m + n; var sub = (int m, int n) => return m - m; // error: ruturn 是代码语句,箭头函数不能使用代码语句 add(1 , 2); } - 当方法作为参数传递给高阶方法时,可以使用匿名方法
也可以使用箭头函数为高阶方法传参// 匿名函数 void main() { var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums']; list.forEach((i) { print(list.indexOf(i).toString() + ': ' + i); }); }// 匿名函数 void main() { var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums']; // 转换为箭头函数时,要去掉语句后面的分号, // 有分号就是语句,没有分号就变成了表达式,符合箭头函数要求 list.forEach((i) => {print(list.indexOf(i).toString() + ': ' + i)}); // 或 list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i)); } - Dart是静态作用域语言,编译时变量的作用域就已经确定(这点也和js不同,前端开发人员需注意)
// 静态作用域 int a = 5; class Test { int a = 6; int getA() { return a; } } void main() { var obj = new Test(); print(obj.getA()); // 6 var fun = obj.getA; print(fun()); // 6 }
操作符
- 除法( / ), 整除(~/)
void main() { print('5/2 = ${5 / 2}'); // 5/2 = 2.5 print('5~/2 = ${5 ~/ 2}'); // 5~/2 = 2 } - 类型转换(as), 类型判断(is、is!), as 只能从父类型转子类型, is 判断变量是某种类型, is!和is相反,判断变量不是某种类型
void main() { num a = 123; // print(a.isOdd); // error: isOdd 不是num的成员变量 print((a as int).isOdd);// isOdd 是int的成员方法,所有a必须转换成int类型后再调用 print('a is not String ? ${a is! String}'); // a is not String ? true print('a is int ? ${a is int}'); // a is int ? true } - ??= 为值为null的变量赋值
void main() { var a; a ??= 1; // 赋值前a = null,赋值后 a=1 a ??= 2; // 赋值前 a = 1, 赋值后 a=1 print(a); // 1 } - expr1 ?? expr2, 等价于 expr1 != null ? expr1 : expr2
void main() { var a; var b = 1; print(a ?? b); // 1 a = 0; print(a ?? b); // 0 } - 级联操作(
..)可以在同一个对象上连续调用多个函数及访问成员变量// '..'不同于'.',不要求函数有返回值,'..'相当于普通函数执行后返回‘this’ class Car { void move(String direction, double distance) { print('小汽车向${direction}行驶了${distance} 千米'); } Car run(String direction, double distance) { print('小汽车向${direction}行驶了${distance} 千米'); return this; } } void main() { Car car = new Car(); car..move('东', 3)..move('南', 4)..move('西', 4)..move('北', 4); car..move('东', 3)..run('西', 3)..run('北', 4).run('西', 4).run('北', 4); } - a?.b 如果a为null,则返回null,否则返回a.b
void main() { int a; // print(a.isOdd); // error: a未赋值,不能访问成员变量和成员函数 print(a?.isOdd); // 相当于 if (a == null) { print(null); } else { print(a.isOdd); } }
类
- 每个对象都是一个类的实例,所有的类都集成于Object
void main() { int a = 1; print(a is Object); // true } - 每个类都只能有一个父类,但是可以同时实现多个接口,一个父类可以同时被多个子类继承
class Tiger extends Animal implements Fly, Swim { // todo } class Dog extends Animal { // todo } - 每个实例变量都会自动生成一个getter方法,Non-final实例变量还会自动生成一个setter方法
class Test { int a; // 相当于 // int _a; // int get a => _a; // set a(int val) => this._a = val; } - 定义一个和类名字一样的方法就定义了一个构造函数,还可以带有其他可选的标识符,如果没有定义,会生成一个不带参数的默认构造函数,构造函数不会被继承
class Parent { String name; Parent(this.name); } class Child extends Parent { Child(String name) : super(name); Child.create(String name) : super(name); } void main(){ var zhangsan = Child('张三'); var lisi = Child.create('李四'); } - 可以使用abstract来定义抽象类,抽象类不能被实例化。抽象类通常含有抽象方法,抽象方法只有方法签名,没有实现。
abstract class Animal { // 抽象方法 void moving(); } - 用extends来实现继承,用implements来实现接口,使用@override来重新父类方法
class Animal { final String name; Animal(this.name); void moving() { print('${this.name}正在移动'); } } abstract class Fly { // 抽象方法 void fly(); } class Tiger extends Animal implements Fly { Tiger() : super('老虎'); @override void fly() { print('如虎添翼'); } } - 用static定义静态变量和静态方法
class Calculator { static int Add(int m, int n) { return m + n; } } void main(){ print(Calculator(1, 2)); }
库的使用
- 通过
import来引入库 - 引用内部库
import 'dart:schema',如:import 'dart:io'; - 引用外部库
import 'package:schema', 如:import 'package:utils/utils.dart'; - 可以通过
as来指定库前缀,如import 'package:utils/utils.dart' as utils; - 可以通过
show和hide来部分导入库 - 可以通过
deferred as延迟加载一个库
dart 核心库
dart:core提供了基础类型、集合和其他少量但是非常核心的功能,dart应用会自动导入这个库。dart:convert提供了一些用来转换 JSON 和 UTF-8 的转换器,还可以自定义 新的转换器。dart:async异步编程通常使用回调函数,但是 Dart 提供了另外的 选择: Future 和 Stream 对象。dart:html为基于web的应用提供了操作Dom元素和使用HTML5 API的功能。dart:math提供了常用的数学运算功能。dart:io提供了一下文件读写、进程访问、sockets等相关的功能,只有命令行应用可以使用。
PUB
pub类似于node的npm,用于管理dart应用的包,详情参见pub.dev/
总结
了解了上面这些基础语法,基本上就可以看懂一些dart示例和源码了,想有所成,了解这些还是远远不够的,但是这些可以作为一个开始,作为学习dart的起点。
参考
- 官方文档:dart.dev/guides
- Pub网站: pub.dev/
- 中文官网:dart.goodev.org/
- 三十分钟入门:www.bilibili.com/video/av327…
- 系列视频:www.bilibili.com/video/av524…
关于我们
快狗打车前端团队专注前端技术分享,定期推送高质量文章,欢迎关注点赞。
文章同步发布在公众号哟,想要第一时间得到最新的资讯,just scan it !
