主题
Dart 语言基础
一、环境准备
vscode 安装 Dart 和 Code Runner
创建 .dart 结尾的文件,点箭头可运行文件
二、变量的声明
1. var 与 dynamic
(1)var
可以接收任何类型,程序会根据变量的值自动追加类型;类型一旦确定后则不能更改其他类型
(2)dynamic
可以接收任何类型的变量,后期可以改变类型
2. const 与 final
(1)const
定义编译时的常量;一旦声明,变量必须赋值
(2)final
定义运行时的常量,可以先定义不赋值,且只可以被赋值一次
dart
void main(){
final time = DateTime.now();
print(time);
}3. late
显式声明一个非空的变量,但不初始化
延迟初始化变量
dart
late String temperature = _readThermometer(); // Lazily initialized.如果 temperature 这个变量没有被使用的话,_readThermometer() 这个函数不会被调用
三、内置类型
1. int 与 double
dart
int a = 12;
double b = 20.23;字符串和数字之间转换:
- toString()
number 类型转为 String 类型
dart
void main() {
var a = 12.2;
var b = a.toString();
print(b is String);//true
}- int.parse()
String 类型转 int 类型
dart
void main(){
String a = '123';
var myNum = int.parse(a);
print(myNum is int); //true
}- double.parse()
String 类型转 double 类型
dart
void main(){
String a = '123.2';
var myNum = double.parse(a);
print(myNum is double); //true
}2. String
以 ${表达式} 的形式使用表达式,如果表达式是一个标识符,可以省略掉 {}
dart
void main(){
String str1 = '你好';
String str2 = 'a';
print('$str1 ${str2.toUpperCase()}');
}3. bool
dart
void main(){
bool a = true;
print('$a');
}4. List
dart
void main(){
var a = [{'name':'1' //对象中的key必须加引号}];
print(a); //[{name: 1}, 2]
}可以使用扩展操作符(...)将一个 List 中的所有元素插入到另一个 List 中
dart
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);如果扩展操作符右边可能为 null,你可以使用 ...? 来避免产生异常
dart
var list2 = [0, ...?list];
assert(list2.length == 1);使用 if 来创建一个 List,它可能包含 3 个或 4 个元素:
dart
var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];使用 for 将列表中的元素修改后添加到另一个列表中
dart
void main() {
var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
print(listOfStrings[1] == '#1');
}增删改查
dart
List list1 = [];
List list2 = [2];
list1.add(1); //增加单个元素
list1.addAll(list2); //增加多个元素
list1.remove(1) //删除指定项使用类的方式创建数组对象,以便拥有更好的类型推断与代码提示功能
dart
import 'package:flutter/material.dart';
class HomeList {
HomeList({this.screen, this.path = ''});
Widget? screen;
String path;
static List<HomeList> homelist=[
HomeList(
screen:const Text('1'),
path: '1'
)
];
}5. Set
一组特定元素的无序集合,可以去重
dart
void main() {
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens); //向已存在的 Set 中添加项目
print(elements);
}6. Map
每个键只能出现一次,值可以重复出现多次
键名只能使用 dart 内置类型,如 String 类型,不能使用变量 name
dart
void main() {
var obj = {
'name':'张三'
};
print(obj['name']);
}获取 key 值:obj.keys
7. enum
dart
enum Color { red, green, blue }
void main() {
print(Color.red.index); //0
print(Color.green.name); //green
}四、运算符
1. is 与 as
(1)is 判断数据类型
dart
void main(){
var obj = {
'name':'张三',
'age':'21',
'work':['程序员','外卖员']
};
if(obj is Map){
print(obj);//{name: 张三, age: 21, work: [程序员, 外卖员]}
}
}(2)as 类型断言
dart
(employee as Person).firstName = 'Bob';2. ??= 与 ??
(1)??= 如果变量为空则赋值,否则不赋值
dart
void main(){
int a;
a ??= 9;
print(a); //9
int b=10;
b ??= 11;
print(b); //10
}(2)?? 如果变量为空则返回默认值
dart
void main(){
var a;
var b = a ?? 10;
print(b); //10
}3. .. 与 ?..
(1)联级运算符 ..
dart
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;相当于
dart
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;(2)?..
dart
querySelector('#confirm') // Get an object.
?..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();相当于
dart
var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();4. isEmpty
判断值是否为空
dart
void main() {
String password = '';
print(password.isEmpty); //true
}五、异步
1. Future
类似于 Promise,处理异步操作;Future 所有 API 的返回值仍然是一个 Future 对象,可链式调用
(1)Future.then
成功后的回调
dart
Future.delayed(Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});(2)Future.catchError
捕获错误
dart
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print("success");
}).catchError((e){
//执行失败会走到这里
print(e);
});(3)Future.whenComplete
结束时候的回调
dart
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});(4)Future.wait
等待多个异步任务执行结束的回调
dart
Future.wait([
// 2秒后返回结果
Future.delayed(Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});4 秒后会在控制台中看到「hello world」
六、Stream
可以接收多个异步操作的结果(成功或失败),常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等
dart
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});上面的代码依次会输出:
text
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3七、async/await
异步任务串行化
dart
task() async {
//使用try...catch捕获异常
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}与 JavaScript 不同,因为函数名前要加返回值的类型,所以 async 放在函数名的后面
八、类
声明一个与类名一样的函数即可声明一个构造函数
dart
void main() {
//实例化时,可省略 new 关键字
var p = Person('张三', 12);
var p2 = Person('李四', 20);
p.getInfo(); //张三--12
p2.getInfo(); //李四--20
}
class Person {
String name;
int age;
//dart的语法糖,相当于this.name = name;
Person(this.name, this.age);
//方法中可省略this获取变量
void getInfo() {
print('$name--$age');
}
}1. 构造函数参数为对象
可使用 required 关键字代表该字段必传;或者给参数一个默认值;或者使用可选操作符 ?
dart
void main() {
var p = Person(name: '张三', age: 12);
var p2 = Person(name: '李四', age: 20);
p.getInfo(); //张三--12
p2.getInfo(); //李四--20
}
class Person {
String name;
int age;
int? scale;
Person({required this.name, this.age = 0, this.scale});
//字符串变量使用''包裹
void getInfo() {
print('$name--$age');
}
}2. 抽离类
在 Dart 中,文件中的类不需要 export 导出,直接在需要的页面用 import 导入。并且不需要用 './' 表示同级目录
Person.dart
dart
class Person {
String name;
int age;
Person(this.name, this.age);
getInfo() {
print('$name--$age');
}
}index.dart
dart
import 'Person.dart';
void main() {
var p = Person('张三', 12);
p.getInfo();
}3. 私有属性和方法
在定义变量时,用下划线表示私有属性(只有该类分离到别的文件才生效,如果在同一个页面不生效)
dart
//Pserson.dart
class Person{
String name;
int age;
String _score = '98';
Person(this.name,this.age);
getInfo(){
print('${this.name}--${this.age}--${this._score}');
}
}dart
//index.dart
import 'Person.dart';
void main() {
var p = Person('张三',12);
p.getInfo();
}此时可通过 p.name 访问公有属性,但是通过 p.score 访问不到私有属性。私有属性可在当前类中调用
4. static 静态成员
静态方法只能访问静态成员,非静态方法没有限制
dart
void main() {
Person.show();
}
class Person {
static String name = '张三';
int age = 20;
static void show() {
print('$name');
}
}5. 继承
使用 extends 关键词来继承父类,并可使用 super 关键字引用一个父类
dart
void main() {
var s = Student('张三', 10, 100);
s.show(); //姓名:张三--年龄:10
s.studentShow(); //张三--100
}
class Person {
String name;
int age;
Person(this.name, this.age);
void show() {
print('$name--$age');
}
}
class Student extends Person {
int score;
//使用(:)指定需要重定向到的其它构造函数
Student(String name, int age, this.score) : super(name, age);
void studentShow() {
print('$name--$score');
//使用super调用父类中的方法
super.show();
}
//覆写父类中的方法
@override
void show() {
print('姓名:${this.name}--年龄:${this.age}');
}
}@override 的作用:
可以放注释用,让人一看就知道覆写了父类中的方法
编辑器可以给你验证
@override下面的方面名是否是你父类所有的,如果没有则报错(一个@override对于一个方法)
6. abstract 抽象类
Dart 中没有方法体的方法为抽象方法
子类继承抽象类必须实现里面的抽象方法
抽象类不能被实例化
extends 和 implements 的区别:
如果要复用抽象类里面的方法,并且要用抽象方法约束子类,使用 extends
如果只是把抽象类当做接口,使用 implements
dart
void main() {
var d = new Dog();
d
..eat() //小狗吃
..show(); //我是抽象类中的普通方法
var c = new Cat();
c.eat(); //小猫吃
}
//抽象类
abstract class Animal {
eat(); //抽象方法
show() {
print('我是抽象类中的普通方法');
}
}
class Dog extends Animal {
@override
eat() {
print('小狗吃');
}
}
class Cat extends Animal {
@override
eat() {
print('小猫吃');
}
}7. 接口
在 dart 中,使用抽象类来定义接口
接口中没有公共方法,只有抽象方法与变量;抽象方法和变量都必须在类中实现
lib/DB.dart
dart
abstract class DB {
String url;
add(String msg);
delete();
}lib/Mongdb.dart
dart
import 'DB.dart';
class Mongdb implements DB {
Mongdb(this.url);
@override
String url;
@override
add(String msg) {
print('$url----$msg');
}
@override
delete() {}
}lib/Mysql.dart
dart
import 'DB.dart';
class Mysql implements DB {
Mysql(this.url);
@override
String url;
@override
add(String msg) {
print('$url----$msg');
}
@override
delete() {}
}index.dart
dart
import 'lib/Mysql.dart';
import 'lib/Mongdb.dart';
void main() {
var mysql = Mysql('XXXXX');
mysql.add('123'); // XXXXX----123
var mongdb = Mongdb('!!!!');
mongdb.add('456'); // !!!!----456
}继承多个接口
dart
void main() {
C('张三', 20)..send();
}
abstract class DB {
String url = '';
add(String msg);
delete();
}
abstract class A {
String name = '';
send();
}
abstract class B {
String name = '';
int? age;
}
class C implements A, B {
C(this.name, this.age);
@override
int? age;
@override
String name = '';
@override
send() {
print('$name -- $age');
}
}8. mixins
作为 mixins 的类只能继承自 Object,不能是其他类的子类
作为 mixins 的类不能有构造函数
一个类可以混入多个 mixins 类
mixins 不是继承,也不是接口,而是一种全新的特性
通过 with 关键字实现混入
dart
void main() {
C('张三', 12)
..info() //张三的年龄12
..send(); //张三的年龄12:分数95
}
class Person {
String name;
int age;
Person(this.name, this.age);
void info() {
print('$name的年龄$age');
}
}
class A {
String score = '95';
}
class B {}
class C extends Person with A, B {
C(String name, int age) : super(name, age);
void send() {
print('$name的年龄$age:分数$score');
}
}注意:定义的变量与方法不能重,不然会覆盖(后面覆盖前面)
九、泛型、类型别名
1. 泛型
dart
void main() {
FileCache f = FileCache<String>();
f.setKey('name', '张三'); //我是文件缓存,key=name,value=张三
MemoryCache m = MemoryCache<int>();
m.setKey('age', 12); //我是内存缓存,key=age,value=12
}
abstract class cache<T> {
setKey(String key, T value);
}
class FileCache<T> implements cache<T> {
@override
setKey(String key, T value) {
print('我是文件缓存,key=$key,value=$value');
}
}
class MemoryCache<T> implements cache<T> {
@override
setKey(String key, T value) {
print('我是内存缓存,key=$key,value=$value');
}
}T 相当于类型占位符,可用其他大写字母代替
2. 类型别名 typedef
dart
typedef Success<T> = Function(T data);十、库
1. 使用库
dart
import 'dart:html';2. 指定库前缀
dart
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();3. 导入库的一部分
dart
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;4. 延迟加载库
使用 deferred as 关键字来标识需要延时加载的代码库:
dart
import 'package:greetings/hello.dart' deferred as hello;当实际需要使用到库中 API 时先调用 loadLibrary 函数加载库:
dart
Future<void> greet() async {
//可以调用多次,代码库只会被加载一次
await hello.loadLibrary();
hello.printGreeting();
}十一、jsonEncode、jsonDecode
jsonEncode:实例对象转 JSON,jsonDecode:JSON 转 Map
dart
import 'dart:convert';
import 'Person.dart';
void main() {
User user = User(name: '张三', id: 1);
print('User对象: $user'); //Instance of 'User'
//实例对象转JSON,实例对象中需有toJson方法
var data = jsonEncode(user);
print('jsonEncode: $data'); //{"name":"张三","id":1}
//json转Map
Map<String, dynamic> user1 = jsonDecode(data);
print('jsonDecode: $user1'); //{name: 张三, id: 1}
print(user1["name"]); //张三
//Map转实例对象
User user2 = User.fromJson(user1);
print('fromJson: $user2'); //Instance of 'User'
print(user2.name); //张三
}
//Person.dart
class User {
String? name;
int? id;
User({this.name, this.id});
User.fromJson(Map<String, dynamic> json) {
name = json['name'];
id = json['id'];
}
Map<String, dynamic> toJson() => {'name': name, 'id': id};
}