Flutter第四节------核心概念学习笔记:从基础语法到异步编程

目录

[1. 引言](#1. 引言)

[2. 控制流:Switch 语句](#2. 控制流:Switch 语句)

[3. 面向对象编程:继承与构造函数](#3. 面向对象编程:继承与构造函数)

[3.1 构造函数继承](#3.1 构造函数继承)

[3.2 抽象类](#3.2 抽象类)

[3.3 类的混入(Mixin)](#3.3 类的混入(Mixin))

[4. 异步编程:Future 与 async/await](#4. 异步编程:Future 与 async/await)

[4.1 Future 的基本使用](#4.1 Future 的基本使用)


1. 引言

今天的学习主要围绕 Dart 语言的核心概念展开,涵盖了控制流、面向对象编程和异步处理等关键知识点。通过代码示例和概念解析,我们可以系统地掌握 Dart 语言的基础语法和高级特性。Dart 作为一门现代化的面向对象编程语言,由 Google 开发并广泛应用于 Flutter 跨平台应用开发中。它不仅具备静态类型语言的严谨性,还拥有动态语言的灵活性,支持高效的 JIT(即时编译)和 AOT(提前编译)两种编译模式。

在学习 Dart 的过程中,我们需要重点关注其独特的语言特性和设计哲学。Dart 强调简洁、高效和可维护性,提供了丰富的标准库和现代化的语法糖。无论是构建简单的命令行工具还是复杂的移动应用,掌握 Dart 的核心概念都是成功的关键。本文将深入探讨控制流、面向对象编程和异步处理这三个核心领域,通过详细的代码示例和实际应用场景,帮助读者建立完整的知识体系。

2. 控制流:Switch 语句

Dart 中的 switch 语句用于基于表达式的值执行多分支选择。与 if-else 链相比,switch 在处理多个固定值的情况时更加清晰简洁。在 Dart 中,switch 语句不仅支持传统的整数和字符串匹配,还支持枚举类型和编译时常量,提供了更强大的模式匹配能力。

Dart 复制代码
void main(List<String> args) {
    int State = 1;
    switch(State) {
       case 1: 
           print("待付款"); 
           break;
       case 2: 
           print("待发货"); 
           break;
       case 3: 
           print("待收货"); 
           break;
       default: 
           print("未知状态"); 
           break;
    }
}

这个示例展示了 switch 语句的基本用法。在实际开发中,switch 语句常用于处理状态机、菜单选择、错误码映射等场景。Dart 的 switch 语句相比其他语言有一些独特之处:

  • 类型安全: switch 表达式可以是整数、字符串或编译时常量,Dart 会进行严格的类型检查
  • 完整的控制流: 每个 case 子句必须以 breakreturncontinuethrow 结束,防止意外穿透
  • 默认处理: default 子句处理所有未匹配的情况,确保逻辑完整性
  • 表达式支持: Dart 2.3+ 支持在 case 中使用表达式,提供了更灵活的匹配逻辑

让我们看一个更复杂的示例,展示 switch 语句的高级用法:

Dart 复制代码
enum OrderStatus { pending, processing, shipped, delivered, cancelled }

void handleOrder(OrderStatus status) {
  switch (status) {
    case OrderStatus.pending:
      print('订单待处理,请耐心等待');
      startProcessing();
      break;
    case OrderStatus.processing:
      print('订单处理中,预计24小时内发货');
      updateInventory();
      break;
    case OrderStatus.shipped:
      print('订单已发货,物流信息已更新');
      sendShippingNotification();
      break;
    case OrderStatus.delivered:
      print('订单已送达,感谢您的购买');
      requestReview();
      break;
    case OrderStatus.cancelled:
      print('订单已取消,退款将在3-5个工作日内处理');
      processRefund();
      break;
  }
}

在这个示例中,我们使用了枚举类型作为 switch 表达式,每个 case 对应一个具体的枚举值。这种写法不仅类型安全,还能在编译时检查是否处理了所有可能的情况(当使用枚举时,Dart 会提示处理所有枚举值)。

3. 面向对象编程:继承与构造函数

Dart 支持单继承,子类通过 extends 关键字继承父类。构造函数继承是面向对象编程中的重要概念。在 Dart 中,继承不仅仅是代码复用的手段,更是实现多态和抽象的基础。通过继承,子类可以获得父类的所有公共和受保护成员,同时可以重写父类的方法以实现特定的行为。

Dart 的继承机制遵循以下原则:

  • 单继承: 每个类只能直接继承一个父类,这简化了继承链的管理
  • 多层继承: 支持多级继承,形成继承层次结构
  • 方法重写: 子类可以重写父类的方法,使用 @override 注解明确意图
  • super 关键字: 用于访问父类的成员,包括方法和属性

3.1 构造函数继承

子类构造函数可以通过 super 关键字调用父类构造函数。构造函数继承是确保对象正确初始化的关键环节,Dart 提供了多种方式来实现构造函数继承:

  • 隐式调用: 如果父类有无参构造函数,子类构造函数会自动调用。这是最简单的继承方式,适用于父类不需要特殊初始化参数的场景。
  • 显式调用: 使用 super(参数) 在子类构造函数体中调用父类构造函数。这种方式允许在调用父类构造函数之前或之后执行额外的初始化逻辑。
  • 初始化列表: 使用 : super(参数) 在初始化列表中调用。这是 Dart 特有的语法,允许在构造函数体执行之前完成父类构造函数的调用和成员初始化。

让我们通过一个完整的示例来理解构造函数继承的实际应用:

Dart 复制代码
class Vehicle {
  String brand;
  int year;
  
  // 父类构造函数
  Vehicle(this.brand, this.year) {
    print('Vehicle 构造函数被调用: $brand, $year');
  }
  
  void displayInfo() {
    print('品牌: $brand, 生产年份: $year');
  }
}

class Car extends Vehicle {
  String model;
  int doors;
  
  // 子类构造函数,使用初始化列表调用父类构造函数
  Car(String brand, int year, this.model, this.doors) 
      : super(brand, year) {
    print('Car 构造函数被调用: $model, $doors门');
  }
  
  @override
  void displayInfo() {
    super.displayInfo(); // 调用父类方法
    print('型号: $model, 车门数: $doors');
  }
}

void main() {
  var myCar = Car('Toyota', 2023, 'Camry', 4);
  myCar.displayInfo();
}

super 函数专门用于调用父类的方法和构造函数,确保继承链的正确初始化顺序。在 Dart 中,构造函数的执行顺序遵循以下规则:

  1. 初始化列表(包括父类构造函数的调用)
  2. 父类的构造函数体
  3. 子类的构造函数体

这种顺序确保了父类先于子类完成初始化,避免了子类访问未初始化的父类成员的风险。

3.2 抽象类

抽象类使用 abstract 关键字定义,不能直接实例化,主要用于定义接口和部分实现。抽象类是面向对象设计中实现多态和代码复用的重要工具,它允许我们定义一组方法的签名而不提供具体实现,强制子类提供这些方法的实现。

  • 抽象方法: 可以包含抽象方法(没有方法体),这些方法必须在子类中实现
  • 具体方法: 也可以包含具体实现的方法,为子类提供默认行为
  • 实现要求: 子类必须实现所有抽象方法,否则子类也必须声明为抽象类
  • 设计用途: 用于定义通用接口和共享行为,建立类之间的契约

抽象类的典型应用场景包括:

Dart 复制代码
abstract class Shape {
  // 抽象方法,子类必须实现
  double area();
  double perimeter();
  
  // 具体方法,子类可以继承或重写
  void display() {
    print('面积: ${area()}, 周长: ${perimeter()}');
  }
}

class Rectangle extends Shape {
  double width;
  double height;
  
  Rectangle(this.width, this.height);
  
  @override
  double area() => width * height;
  
  @override
  double perimeter() => 2 * (width + height);
}

class Circle extends Shape {
  double radius;
  
  Circle(this.radius);
  
  @override
  double area() => 3.14159 * radius * radius;
  
  @override
  double perimeter() => 2 * 3.14159 * radius;
}

void main() {
  var shapes = [Rectangle(5, 3), Circle(4)];
  for (var shape in shapes) {
    shape.display(); // 多态调用
  }
}

在这个示例中,Shape 抽象类定义了几何形状的通用接口,而 RectangleCircle 类提供了具体的实现。这种设计模式使得代码更加模块化和可扩展。

3.3 类的混入(Mixin)

Mixin 是 Dart 中实现代码复用的重要机制,它解决了单继承的限制,允许在不同类层次结构中复用代码。Mixin 本质上是一种在多个类层次结构中复用类代码的方式,而不需要这些类有共同的父类。

  • 定义方式: 使用 mixin 关键字定义混入对象
  • 应用方式: 通过 with 关键字将混入对象应用到当前类
  • 多重混入: 一个类可以使用多个 mixin,用逗号分隔
  • 限制条件: Mixin 不能有构造函数,用于提供可复用的方法实现
  • 冲突解决: 当多个 mixin 有同名方法时,最后应用的 mixin 方法会覆盖前面的

Mixin 的典型应用场景包括为类添加通用功能,如日志记录、序列化、验证等:

Dart 复制代码
mixin Logging {
  void log(String message) {
    print('${DateTime.now()}: $message');
  }
}

mixin Validation {
  bool isValidEmail(String email) {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
  }
}

class User with Logging, Validation {
  String name;
  String email;
  
  User(this.name, this.email) {
    log('用户 $name 被创建');
  }
  
  void register() {
    if (isValidEmail(email)) {
      log('用户 $name 注册成功');
      // 注册逻辑
    } else {
      log('用户 $name 邮箱格式无效');
    }
  }
}

void main() {
  var user = User('张三', 'zhangsan@example.com');
  user.register();
}

Mixin 解决了单继承的限制,允许在不同类层次结构中复用代码。与接口和抽象类相比,Mixin 提供了更灵活的代码复用方式:

  • 与继承对比: 继承是"is-a"关系,Mixin 是"has-a"能力
  • 与接口对比: 接口只定义契约,Mixin 提供具体实现
  • 组合优势: 可以同时应用多个 Mixin,实现功能组合

4. 异步编程:Future 与 async/await

Dart 的异步编程模型基于 Future 和 Stream,提供了简洁的语法处理异步操作。在现代应用开发中,异步编程是处理 I/O 操作、网络请求、文件读写等耗时任务的关键技术。Dart 的异步模型设计优雅,既保持了代码的可读性,又提供了强大的并发处理能力。

理解 Dart 的异步编程需要掌握以下几个核心概念:

  • 事件循环: Dart 使用单线程事件循环模型,通过事件队列处理异步任务
  • Future: 表示一个可能在未来完成的值或错误
  • async/await: 让异步代码看起来像同步代码的语法糖
  • Stream: 表示一系列异步事件的序列

4.1 Future 的基本使用

Future 表示一个可能在未来某个时间完成的值或错误。它是 Dart 异步编程的基础,用于处理一次性异步操作的结果。Future 有三种状态:未完成(uncompleted)、已完成带有值(completed with a value)、已完成带有错误(completed with an error)。

  • then():接收成功状态的回调,处理异步操作成功的结果。可以链式调用多个 then() 方法,每个方法接收前一个 Future 的结果。
  • catchError():接收失败状态的回调,处理异步操作发生的错误。可以捕获特定类型的错误,提供精细的错误处理。
  • whenComplete():无论成功或失败都会执行的回调,常用于资源清理等操作。

让我们通过一个完整的网络请求示例来理解 Future 的使用:

Dart 复制代码
import 'dart:convert';
import 'dart:io';

Future<Map<String, dynamic>> fetchUserData(int userId) async {
  // 模拟网络延迟
  await Future.delayed(Duration(seconds: 2));
  
  // 模拟网络请求
  var httpClient = HttpClient();
  try {
    var request = await httpClient.getUrl(
      Uri.parse('https://api.example.com/users/$userId')
    );
    var response = await request.close();
    
    if (response.statusCode == 200) {
      var responseBody = await response.transform(utf8.decoder).join();
      return jsonDecode(responseBody);
    } else {
      throw HttpException('请求失败,状态码: ${response.statusCode}');
    }
  } finally {
    httpClient.close();
  }
}

void main() {
  print('开始获取用户数据...');
  
  fetchUserData(123)
    .then((userData) {
      print('获取用户数据成功:');
      print('用户名: ${userData['name']}');
      print('邮箱: ${userData['email']}');
      print('注册时间: ${userData['registeredAt']}');
    })
    .catchError((error) {
      print('获取用户数据失败: $error');
      // 可以在这里进行错误恢复或重试逻辑
    })
    .whenComplete(() {
      print('用户数据获取操作完成');
    });
  
  print('继续执行其他任务...');
}

这个示例展示了 Future 的完整使用流程,包括成功处理、错误处理和完成回调。在实际开发中,Future 常用于以下场景:

  • 网络请求: HTTP API 调用、WebSocket 通信
  • 文件操作: 读写文件、目录遍历
  • 数据库操作: 查询、插入、更新数据
  • <
相关推荐
FoldWinCard1 小时前
D4 Linux 进程 内存 等命令
linux·运维·服务器
在线OJ的阿川1 小时前
仿muduo库实现高并发服务器
linux·服务器·c++
北冥you鱼1 小时前
Go Modules 使用指南:从入门到精通
开发语言·后端·golang
l1t1 小时前
duckdb 1.6dev新增的.manual命令
开发语言·数据库
你怎么知道我是队长2 小时前
JavaScript的函数介绍
开发语言·前端·javascript
j7~2 小时前
【Linux 系统】二十.进程间通信(共享内存、消息队列、信号量)
linux·运维·消息队列·共享内存·信号量·system v
YMWM_2 小时前
python-venv虚拟环境
linux·开发语言·python
电商API_180079052472 小时前
电商ERP 自动同步订单功能实现拆解与技术手段
服务器·前端·网络·爬虫
万俟淋曦2 小时前
【ROS2】动作通信机制 Action 代码示例(C++版)
linux·人工智能·机器人