Skip to content

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 ​

  1. 显式声明一个非空的变量,但不初始化

  2. 延迟初始化变量

dart
late String temperature = _readThermometer(); // Lazily initialized.

如果 temperature 这个变量没有被使用的话,_readThermometer() 这个函数不会被调用

三、内置类型 ​

1. int 与 double ​

dart
int a = 12;
double b = 20.23;

字符串和数字之间转换:

  1. toString()

number 类型转为 String 类型

dart
void main() {
  var a = 12.2;
  var b = a.toString();
  print(b is String);//true
}
  1. int.parse()

String 类型转 int 类型

dart
void main(){
  String a = '123';
  var myNum = int.parse(a);
  print(myNum is int); //true
}
  1. 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 的作用:

  1. 可以放注释用,让人一看就知道覆写了父类中的方法

  2. 编辑器可以给你验证 @override 下面的方面名是否是你父类所有的,如果没有则报错(一个 @override 对于一个方法)

6. abstract 抽象类 ​

  1. Dart 中没有方法体的方法为抽象方法

  2. 子类继承抽象类必须实现里面的抽象方法

  3. 抽象类不能被实例化

extends 和 implements 的区别:

  1. 如果要复用抽象类里面的方法,并且要用抽象方法约束子类,使用 extends

  2. 如果只是把抽象类当做接口,使用 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 ​

  1. 作为 mixins 的类只能继承自 Object,不能是其他类的子类

  2. 作为 mixins 的类不能有构造函数

  3. 一个类可以混入多个 mixins 类

  4. 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};
}