main
// main函数入口
main() {
print("你好, dart");
}
// 表示main函数没有返回值
// 在这里写方法,也能运行
void main() {
print("你好, dart");
}
变量与常量
变量
使用var
来定义变量,可以自动推断变量类型
var str = "this is a string";
也可以使用具体的类型关键词
来定义变量
// String
String str = "this is a string";
// int
int myNum = 123;
常量
使用final
和const
修饰符, 它们之间的主要区别
const
值不变,定义变量的时候就得赋值final
可以定义变量的时候不赋值,但只能赋值一次;final不仅有const的编译常量的特性,最重要的它是运行时
const str; // ❌,const常量定义的时候就需要赋值
const str = "123";
str = "231"; // ❌,const定义的常量无法修改
final str;
str = "123"; // ✅,可以定义变量的时候不赋值
str = "232"; // ❌,final只能赋值一次
final str = "123";
str = "232"; // ❌,final只能赋值一次
final time = new DateTime.now(); // ✅,final是运行时(使用时才初始化)
print(time);
const time = new DateTime.now(); // ❌,const不具备运行时, 而DateTime是运行函数
数据类型
String
// 使用String类型关键词定义
String name1 = "jack";
String name2 = 'jack';
// 当有换行文本出现时,使用多个单引号或者多个双引号
String name3 = '''jack
hanse
eric
''';
String name4 = """jack
hanse
eric
""";
字符串拼接
使用$
符号拼接
String str1 = "hello";
String str2 = "dart";
print("$str1 $str2, this is a string"); // 输出:hello dart, this is a string
也可以使用+
拼接
String str1 = "hello";
String str2 = "dart";
print(str1 +" "+ str2 + ", this is a string");
数值类型
int value = 123;
double price = 123.11;
布尔类型
bool check = true;
// dart 有类型匹配特性
var a = 123;
var b = "123";
if (a == b) { // false
print("相等");
}
集合类型
var l1 = ["张三", "李四", false];
var name = l1[0];
int len = l1.length;
/// 通过泛型方式,定义集合
var l2 = <String>["张三", "aaa", "bbb"];
/// 定义空集合,通过add添加数据
var l3 = [];
l3.add("123");
l3.length = 0; // 通过设置length = 0设置长度为0,来移除所有元素
/// 创建一个固定长度的集合
var l4 = List.filled(4, "");
l4[0] = "111";
l4[1] = "222";
var l5 = List<String>.filled(4, ""); // 泛型方式
List常用属性与方法:
- 常用属性
- length 长度
- reversed 翻转, xxx.reversed.toList()
- isEmpty 是否为空
- isNotEmpty 是否不为空
- 常用方法
- add(value) 增加一个元素
- addAll([]) 增加数组
- indexOf(value) 查找值所在的索引
- remove(value) 删除元素,传入具体值
- removeAt(index) 删除元素,传入索引
- fillRange(int start, int end, [E? fillValue]) 批量修改指定位置的元素值
- insert(index, value) 指定位置插入
- insertAll(index, list) 指定位置插入list
- toList() 其他类型转换为list
- join() List拼接为字符串
- split() 字符串转换为List
- forEach 遍历
- map 遍历
- where 筛选, 返回list
- any 判断是否有特定数据,返回true/false
- every
Set:
Set
没有顺序且不能重复的集合,类似于OC
当中的NSSet
var list = new Set();
list.add('aaa');
Maps
通过{}
方式定义对象
/// 与JSON对象相似
var maps = {
"name": "张三",
"age": 18,
};
print(maps['name']);
通过new
方式定义对象
var p = new Map();
p["name"] = "张三";
p["age"] = 19;
print(p['name']);
类型判断
通过is
关键词判断类型
var str = "1234";
if (str is String) {
print("字符串类型");
}
运算符
Dart
中运算符与其他语言基本保持一致,以下这些有特殊:
// 取整
print(12~/5); // 输出:2
print(12/5); // 输出:2.4
// ??= 表示如果后面值为空,就赋值给前面的值, 与OC当中?:相似
var name = null;
name ??= 'James';
print(name); // 输出James
类型转换
Number
与 int
之间的转换
// String 转 int 通过 int.parse()
String str = "123";
var age = int.parse(str);
// var age = double.parse(str); // 转double
print(age);
// int 转 String 通过toString()
int str = 123;
var age = str.toString();
print(age);
// 通过try catch来捕获转换过程中的异常情况
try {
int str = 123;
var age = str.toString();
print(age);
} catch (e) {
}
// 判断是否为空字符串
String str = "";
if (str.isEmpty) {
print("空"); // 输出:空
}
// 判断是否为null
var str = null;
if (str == null) {
print("空");
}
// 判断是否是NaN
var age = 0/0;
if (age.isNaN) {
print("NaN");
}
函数
返回类型 方法名称 (参数1, 参数2, ...) {
return 返回值;
}
void sss(int a) {
print(a);
}
sss(123);
方法中的可选参数:
void sss(int a, [String? age, String? dd]) {
print("$a----$age---$dd");
}
sss(123, "aaa", "bbb"); // 123----aaa---bbb
sss(123); // 123----null---null
命名参数方法:
// 带有命名的参数, 用{}表示
void sss(int a, {String? age, String? dd}) {
print("$a----$age---$dd");
}
sss(123, age: "111", dd: "222"); // 123----111---222
sss(123); // 123----null---null
// 带required表示age参数是必填
void ddd(int a, {required String age, String? dd}) {
print("$a----$age---$dd");
}
方法当做参数传递:
int fn1() {
return 1;
}
fn2(fn) {
print(fn);
}
fn2(fn1());
类
class Person {
var name;
var age;
// 构造方法
Person(int age, String name) {
this.age = age;
this.name = name;
}
// getter 方法
get come {
return "abc";
}
// setter 方法
set come(value) {
this.age = value;
}
String getInfo() {
return "name is ${this.name}, age is ${this.age}";
}
}
main() {
var person = new Person(11, "jack");
person.age = 33;
print(person.come); // 调用getter
print(person.getInfo()); // 调用方法
}
命名构造方法:
class Person {
var name;
var age;
// 命名构造方法
Person.now(int age, String name) {
this.age = age;
this.name = name;
}
getInfo() {
print("name is ${this.name}, age is ${this.age}");
}
}
// 通过这样调用
var person = new Person.now(11, "jack");
默认构造函数只能写一个, 而命名构造函数可以写多个
访问修饰符
Dart
当中并没有其他语言当中的private, public
等关键词来修饰访问权限, 但可以使用_
修饰,把一个方法或者属性定义成私有
(需要将这个类抽离成一个单独的文件)
class Person {
var _name;
var age;
// 构造方法
Person.now(int age, String name) {
this.age = age;
this._name = name;
}
getInfo() {
print("name is ${this._name}, age is ${this.age}");
}
}
抽象类
通过abstract
来定义抽象类,抽象类不能被直接实例化,只有继承
它的子类才可以
abstract class Person {
String strName();
}
// 在抽象类方法中定义的抽象方法,其子类必须要实现
class Child extends Person {
@override
String strName() { // strName方法必须要实现
return "123";
}
}
main() {
var child = new Child();
print(child.strName());
}
extends、implements、with
Dart
当中没有多继承
, 继承后子类重写
或者调用
父类的方法,也可以获取
父类的属性等.
extends
通过extends
继承父类,可以拥有父类的属性,方法, 可以不重写
父类的属性
或方法
class Animal {
var name = "Animal";
eat () {
print("eat");
}
}
class Dog extends Animal {
Dog() {
super.name = "Dog";
}
@override
eat() {
print("${super.name} eat");
}
}
main() {
var s = new Dog();
s.eat();
}
implements
implements
代表实现, 用implements
修饰后,需要重写
所有的属性和方法
class Animal {
var name = "Animal";
eat() {
print("eat");
}
}
class Cow {
drink() {
print("drink");
}
}
class Dog implements Animal, Cow {
@override
String name = "";
@override
drink() {
print("dog drink");
}
@override
eat() {
print("dog eat");
}
}
main() {
var s = new Dog();
s.eat();
}
with
with
代表混入
, 通过with
关键词可以间接的实现多继承
, 但继承的必须是类
如果A类
混入了B类
,那么A类
就可以直接调用B类
里面的方法,且不需要实例化B类
,不需要B类
做单例,也不需要静态被调用的方法,还能混入多个类,这对方法复用带来的极大的便利性,破除了众多限制
class Animal {
var name = "Animal";
eat() {
print("eat");
}
}
class Cow {
drink() {
print("drink");
}
}
class Dog with Animal, Cow {
}
main() {
var s = new Dog();
s.eat();
s.drink();
}
使用with后,不能有构造函数
泛型
T getData<T>(T value) {
return value;
}
var d = getData<String>("str");
async和await
async
是把方法变成异步,await
是等待异步方法执行完成
只有async
方法才能使用await
关键词
如果要调用别的async
方法,必须使用await
关键词
identical
通过identical
判断两个对象内存地址是否一致
var s = 1;
var d = 2;
print(identical(s, d));
Future
Future
是Dart
中提供的一个抽象类、泛型类,它用于封装一段在将来会被执行
的代码逻辑,与promise很相似
创建一个延迟执行的 Future
//延迟三秒执行
Future.delayed(Duration(seconds: 3), () {
print("future delayed");
});
创建一系列的Future,并且会按顺序执行这些Future
Future.forEach([1,2,3], (item) {
return Future.delayed(Duration(seconds: 2),() {
print(item);
});
});
多个Future执行结束后,再通知回调
Future.wait([
Future(() {
return "任务1";
}),
Future(() {
return "任务2";
})
]).then((value) {
print(value[0]+value[1]);
});
多个Future执行,返回最先执行完成的Future的结果
Future.any([
Future.delayed(Duration(seconds: 3), () {
return 333;
}),
Future.delayed(Duration(seconds: 1), () {
return 111;
}),
]).then((value) {
print(value); // 111
});
Future.cathcError
注册一个回调,来处理有error
的Future
onError
只能处理当前的错误Future,而不能处理其他有错误的Future。catchError
可以捕获到Future链中抛出的所有错误。
new Future.error('boom!').catchError(print);
Future.whenComplete
Future.whenComplete
总是在Future完成后
调用,不管Future的结果是正确的
还是错误的
。
scheduleMicrotask
多个异步下载任务,其中一个任务需要优先执行
/// 任务优先执行
getData() {
print('getData 开始执行');
Future(() {
print('任务 1 开始执行');
return '任务1';
}).then((value) {
sleep(const Duration(seconds: 2));
print('任务 2 开始执行');
return '任务2';
});
print('任务 C');
sleep(const Duration(seconds: 2));
scheduleMicrotask(() {
print('任务 X');
});
}
无论是事件队列还是微任务队列,都遵循3个原则:
- [微任务事件]级别高于[事件队列]
- 对于队列里添加新队列,新队列要在原先队列执行完之后才执行
- 对于同一类型的队列任务,先进先出
多线程Isolate
Dart
是单线程
语言,但有时候难免会需要用到多线程
的功能,为解决这个困扰,Dart提供了Isolate
来替代多线程
Isolate
有【隔离】
的意思,即多个Isolate之间不共享内存,每个Isolate
有各自的存储空间,也就是说Dart的并发实际上是通过运行多个Isolate产生的结果
int a = 10;
getData() async {
a++;
print('line230 = $a');
sleep(const Duration(seconds: 2));
Isolate.spawn(func, 'message');
sleep(const Duration(seconds: 2));
print('line234 = $a');
}
void func(String message) {
print('line238 --- $a');
a = a + 3;
}
// 执行结果:
// line230 = 11
// line238 --- 10
// line234 = 11
本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.