Flutter学习01——Dart语言基础

65 阅读6分钟

Dart语言

  ‍

1.环境搭建

  ‍

  下载Dart SDK:gekorm.com/dart-window…

  按软件包的方式来安装,最新的Dart会自动配置环境变量,

     ‍

2.基础知识

  ‍

2.1.变量和常量的声明

  ‍

  • 变量
void main(List<String> args) {
  var age = 20; // 值
  print(age);
  age = 21;
  var age1 = 20 + 21; // 表达式
  print(age1);
}

  ‍

注意

  • 变量使用var声明
  • 变量第一次赋值之后,其类型不能改变,即第一次赋值为字符串类型的话,其只能后面给字符串类型的值

  ‍

  ‍

  • 常量
void main(List<String> args) {
  const num = 3.1415926;
  const length = 2 * num * 10;
  print(length);
}

  ‍

void main(List<String> args) {
  final time = DateTime.now();
  print(time);
}

  ‍

注意

  • 常量的值如果是表达式,则表达式中不能有变量
  • 常量不能由变量赋值
  • const 赋值要求是编译时就确定的值
  • final 是运行时被初始化,其值设置后不可更改

  ‍

  ‍

2.2.Dart类型

  ‍

  • 字符串类型
void main(List<String> args) {
  // 基本使用
  String text = '今天是个好日子';
  print(text);
  text = '明天同样是一个好日子';
  print(text);

  // 模板字符串
  String content = '我要在${DateTime.now()}吃饭';
  print(content);

  String flag = '张三';
  content = '我和$flag是好朋友';

  print(content);
}

  ‍

  ‍

  • 数值类型

  int:整数

  num:可以是整数,也可以是小数

  double:小数

  ‍

void main(List<String> args) {
  int friendCount = 3;
  print('我有$friendCount个朋友');

  num rest = 1.5;
  print('我有$rest个假期');

  double appleCount = 1.5;
  print('我要买$appleCount斤的苹果');

  friendCount = appleCount.toInt(); // int 和 double 之间不允许进行相互的赋值
  appleCount = friendCount.toDouble();
  rest = appleCount; // double可以直接赋值给num
  appleCount = rest.toDouble(); // num给double赋值要进行转换
}

  ‍

注意

  • double 、int 类型之间不能直接赋值,需要通过toInt()​、toDoublue()来进行转换【Dart不能隐式转换】
  • num不能直接给double赋值,而double可以直接赋值给num

  ‍

  ‍

  • bool 类型
void main(List<String> args) {
  bool isFinishWork = false;
  print('结束任务的状态$isFinishWork');
}

  ‍

  ‍

  ‍

  • List列表类型
void main(List<String> args) {
  List students = ['张三', '李四', '王五'];
  print(students);

  // 在尾部添加内容
  students.add('小美');
  print(students);

  // 在尾部添加列表
  students.addAll(['赵六', '小豪']);
  print(students);

  // 删除满足内容的第一个
  students.remove('小豪');
  print(students);

  // 删除最后一个
  students.removeLast();
  print(students);

  // 删除索引范围的数据【不删除结束索引位置的元素】
  students.removeRange(0, 2);
  print(students);
}

  ‍

void main(List<String> args) {
  List students = ['张三', '*李四', '*王五'];
  print(students);

  // 遍历列表
  students.forEach((item) {
    print(item);
  });

  // 是否都满足条件
  var isReal = students.every((item) {
    return item.toString().startsWith('*');
  });

  print(isReal);

  // 筛选出满足条件的数据【这里返回的是一个类似于列表类型的数据,所以要转换为列表】
  var isStars = students.where((item) {
    return item.toString().startsWith('*');
  }).toList();

  print(isStars);

  // list的常用属性
  print(students.length); // 长度
  print(students.first); // 获取第一个元素
  print(students.last); // 获取最后一个元素
  print(students.isEmpty); // 判断列表是否为空
}

  ‍

  ‍

  ‍

  • Map 字典类型
void main(List<String> args) {
  Map transMap = {'lunch': '午饭', 'breakfast': '早餐', 'hello': '你好'};
  print(transMap);

  // 通过key获取值
  print(transMap['lunch']);

  // 修改值
  transMap['hello'] = '你非常好';
  print(transMap);

  // 循环字典
  transMap.forEach((key, val) {
    print('$key:$val');
  });

  // 再添加一个字典
  transMap.addAll({'fine': '很好'});
  print(transMap);

  // 判断字典中是否包含某个key
  print(transMap.containsKey('fine'));

  // 删除某个key
  print(transMap.remove('fine'));

  // 清空
  transMap.clear();
  print(transMap);
}

  ‍

  ‍

  • dynamic动态类型

特点:允许变量再运行时自由的改变类型,同时绕过编译时的静态检查

  ‍

void main(List<String> args) {
  dynamic free = '字符串';
  free = 123;
  free = {};
  free = [];
  free = true;
  print(free);
}

  ‍

  • dynamic可以自由的改变类型,无编译检查,方法和属性直接调用

  ‍

  ‍

  ‍

2.3.Dart的空安全机制

  ‍

Dart通过编译静态检查将运行时的空指针提前暴露

  ‍

常用的空安全的操作符:

image-20251018145531-hgjtgoh.png

void main(List<String> args) {
  // 表示变量可空
  String? username = null;

  // 表示前面的变量为null的时候,跳过操作
  username?.startsWith('新');

  // 表示开发者保证前面的变量不为空
  username!.startsWith('牢');

  // 左侧为null时返回右侧默认值
  String displayName = username ?? '老高';
  print(displayName);
}

  ‍

  ‍

  ‍

2.4.运算符

image-20251018150114-zrv56jg.png

  ‍

image-20251018150350-pckmuoj.png

image-20251018150630-voyde0t.png

image-20251018150722-av7ewdt.png

  ‍

2.5.流程控制

  ‍

  • 分支语句 和 三元运算符
void main(List<String> args) {
  // 表示变量可空
  int score = 61;
  if (score >= 60) {
    print('及格');
  } else if (score > 70) {
    print('良好');
  } else if (score < 60) {
    print('不及格');
  }

  print(59 >= 60 ? '及格' : '不及格');
}

  ‍

void main(List<String> args) {
  // 表示变量可空
  int state = 1;
  switch (state) {
    case 1:
      print('情况1');
      break;
    case 2:
      print('情况2');
      break;
    case 3:
      print('情况3');
      break;
    default:
      print('你好');
  }
}

  ‍

  ‍

  • 循环控制
while(条件) {
    循环体
}

continue // 跳出当前循环
break // 跳出整个循环

  ‍

  ‍

for(int i = 0; i < 10;i++) {
    循环体
}

  ‍

  ‍

  ‍

3.Dart的函数

  ‍

返回类型 函数名称(参数列表) {
    函数体
}

  ‍

void main(List<String> args) {
  var number = add(1, 2, 3);
  print(number);
}

int add(int a, int b, int c) {
  return a + b + c;
}

  ‍

  ‍

3.1.函数的参数

  ‍

  • 可选位置参数
void main(List<String> args) {
  print(combine('1', '2'));
}

// 可选位置参数
// 可以给对应可选参数设置默认值
String combine(String a, [String? b, String? c = 'c']) {
  return a + (b ?? "") + (c ?? "");
}

  ‍

  • 可选命名参数
void main(List<String> args) {
  print(combine('1', '2'));
  showPerson("老高", sex: '男');
}

// 可选位置参数
// 可以给对应可选参数设置默认值
String combine(String a, [String? b, String? c = 'c']) {
  return a + (b ?? "") + (c ?? "");
}

// 可选命名参数
void showPerson(String username, {int? age, String? sex}) {
  print('姓名:$username,性别:$sex,年龄:$age');
}

  ‍

  注意:可选命名参数无需关注参数的位置,它是按照参数的名称来传递对应的参数值

  ‍

  ‍

3.2.匿名函数

  ‍

Function 变量名 = () {}

  ‍

void main(List<String> args) {
  test();
  // 传入函数类型的参数
  onTest(test);
}

Function test = () {
  print('测试数据');
};


void onTest(Function callback) {
  callback();
}

  ‍

  ‍

3.3.箭头函数

  ‍

  当函数体只有一行代码逻辑的时候,可以使用箭头函数编写,箭头函数可以省略return关键字

函数名 => 代码逻辑

  ‍

void main(List<String> args) {
  test();
  // 传入函数类型的参数
  onTest(test);

  add(1, 2);
}

Function test = () {
  print('测试数据');
};

void onTest(Function callback) {
  callback();
}

// 箭头函数
int add(int a, int b) => a + b;

  ‍

  ‍

4.类

  ‍

void main(List<String> args) {
  Person p = new Person();
  p.name = '小天';
  p.study();
}

class Person {
  String name = '';
  int age = 0;
  String sex = '男';

  void study() {
    print('$name在学习');
  }
}

  ‍

4.1.类的构造函数

  ‍

  • 默认构造函数
void main(List<String> args) {
  Person p = new Person(name: '小天', age: 15, sex: '男');
  p.study();

  Person pp = new Person(name: '老天', age: 15, sex: '男');
  pp.study();
}

class Person {
  String? name = '';
  int? age = 0;
  String? sex = '男';

 // 默认构造函数
  Person({String? name, int? age, String? sex}) {
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  void study() {
    print('$name在学习');
  }
}

  ‍

  ‍

  • 命名构造函数
void main(List<String> args) {
  Person p = new Person(name: '小天', age: 15, sex: '男');
  p.study();

  Person pp = new Person(name: '老天', age: 15, sex: '男');
  pp.study();

  Person ppp = new Person.createPerson(name: '小白', age: 15, sex: '男');
  ppp.study();
}

class Person {
  String? name = '';
  int? age = 0;
  String? sex = '男';

  Person({String? name, int? age, String? sex}) {
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  // 命名构造函数
  Person.createPerson({String? name, int? age, String? sex}) {
    this.name = name;
    this.age = age;
    this.sex = sex;
  }

  void study() {
    print('$name在学习');
  }
}

  ‍

  ‍

  • 构造函数的语法糖(其不要求参数的顺序)
void main(List<String> args) {
  Person p = new Person(name: '小天', age: 15, sex: '男');
  p.study();

  Person pp = new Person(name: '老天', age: 15, sex: '男');
  pp.study();

  Person ppp = new Person.createPerson(name: '小白', age: 15, sex: '男');
  ppp.study();
}

class Person {
  String? name = '';
  int? age = 0;
  String? sex = '男';

  // 语法糖
  Person({this.name, this.age, this.sex});

  Person.createPerson({this.name, this.age, this.sex});

  void study() {
    print('$name在学习');
  }
}

     ‍

4.2.面向对象的三种性质

  ‍

1.封装

  公有属性和私有属性

  私有属性:属性名以下划线开头的属性都是私有属性,包括私有方法,方法名称只要以下划线开头即可

  ‍

  私有属性和私有方法只能在类的内部访问,外部引入不能使用

  ‍

  ‍

2.继承

  Dart属于单继承

  注意:子类不会继承父类的构造函数,子类必须通过super关键字调用父类的构造函数来确保父类正确初始化

  ‍

void main(List<String> args) {
  Child c = Child(name:'小天',age:15);
  c.study();
}

class Parent {
  String? name;
  int? age;
  Parent({this.name, this.age});

  void study() {
    print('父类$name在学习');
  }
}

class Child extends Parent {
  // 这里子类必须调用父类的构造
  Child({String? name, int? age}) : super(name: name, age: age);

  @override
  void study() {
    // 调用父类的study()
    super.study();

    print('子类的$name在学习');
  }
}

  ‍

  ‍

多态
  • 继承和重写方法
void main(List<String> args) {
  PayBase p = WxPay();
  p.pay();
  PayBase pp = AliPay();
  pp.pay();
}

class PayBase {
  void pay() {
    print('基础支付');
  }
}

class WxPay extends PayBase {
  @override
  void pay() {
    print('wx支付');
  }
}

class AliPay extends PayBase {
  @override
  void pay() {
    print('zfb支付');
  }
}

  ‍

  ‍

  • 抽象类和接口实现
void main(List<String> args) {
  PayBase p = WxPay();
  PayBase pp = AliPay();

  p.pay();
  pp.pay();
}

abstract class PayBase {
  void pay(); // 抽象类不屑具体实现
}

class WxPay implements PayBase {
  @override
  void pay() {
    print('wx支付');
  }
}

class AliPay implements PayBase {
  @override
  void pay() {
    print('zfb支付');
  }
}

  ‍

  ‍

  ‍

4.3.类的混入

  ‍

  Dart允许在不使用传统的继承的方式下,向类中添加新的功能

  方式

  • 使用mixin关键字定义一个对象
  • 使用with关键字将定义的对象混入到当前的对象

  ‍

  特点:一个类支持with多个mixin,调用优先级遵循后来者居上,即后混入的会覆盖先混入的同名方法

void main(List<String> args) {
  Student s = Student(name: '小天');
  s.song(s.name!);

  Teacher t = Teacher(name: '小百');
  t.song(t.name!);
}

mixin Base {
  void song(String name) {
    print('$name在唱歌');
  }
}

class Student with Base {
  String? name;
  int? age;

  Student({this.name, this.age});
}

class Teacher with Base {
  String? name;
  int? age;

  Teacher({this.name, this.age});
}

  ‍

  ‍

5.泛型

void main(List<String> args) {
  // 列表泛型
  List<String> list = [];
  list.add('苹果');
  list.add('香蕉');

  // 字典泛型
  Map<String, int> map = {};
  map['a'] = 10;

  print(getValue<String>('1'));
}

// 函数中的泛型
T getValue<T>(T val) {
  return val;
}

// 类使用泛型
class Student<T> {
  T? name;
}

  ‍

  ‍

  ‍

6.异步编程

  ‍

  Dart 是单线程语言,即同时只能做一件事情,遇到耗时任务就会造成程序堵塞,此时需要异步编程

  ‍

  定义:Dart采用单线程+事件循环的机制来完成耗时任务的处理

  ‍

事件循环

image-20251018165137-ytx4jty.png

  ‍

Dart会先去执行同步代码,然后去执行微任务队列中的任务,然后再去执行事件队列中的事件最后才会执行结束

  ‍

  • 微任务队列:Future.microtask()
  • 事件队列:Future、Future.delayed()、I/O操作(文件、网络)等

  ‍

  ‍

6.1.Future

  ‍

  Future代表一个异步操作的最终结果

  状态:Uncompleted(等待)、Completed with a value(成功)、Completed with a error(失败

  ‍

void main(List<String> args) {
  Future f = Future(() {
    throw Exception();
    // return 'Hello Future';
    // 没有抛出异常,则表示是成功状态
  });

  // value是Future你返回的值
  // then接收成功状态
  f.then((value) {
    print(value);
  });

  // catchError接收失败状态
  f.catchError((err) {
    print('出现错误了');
    print(err);
  });
}

  ‍

  ‍

  • 链式调用
void main(List<String> args) {
  // 三个异步任务使用链式调用
  Future f =
      Future(() {
            return 'Hello world';
          })
          .then((value) {
            return Future(() => 'task1');
          })
          .then((val) {
            return Future(() => '$val task2');
          })
          .then((val) {
            return Future(() => '$val task3');
          })
          .then((val) {
            print(val);
            throw Exception();
          })
          // 只要一个有异常就会直接跳到异常这里的处理
          .catchError((err) {
            print('出现错误');
          });
}

  ‍

  ‍

  • async/await

  注意:async 和 await必须配套出现

  await总是要等到后面的Future执行成功才继续执行下方逻辑

void main(List<String> args) {
  test();
}

void test() async {
  try {
    await Future(() {
      throw Exception();
    });
  } catch (err) {
    print('异步请求出现异常');
  }
}

  ‍

void main(List<String> args) {
  test();
}

void test() async {
  try {
    String res = await Future(() {
      return 'test';
    });

    print(res);
  } catch (err) {
    print('异步请求出现异常');
  }
}