Menu
CoddyTech

类方法中的异步编程

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 80 课,共 110 课。

现在你已经了解了如何使用工厂方法处理异步初始化,接下来看看如何让常规实例方法变为异步方法。这很简单,只需在任意方法前添加 async,并让它返回一个 Future。

class WeatherService {
  String _location;
  
  WeatherService(this._location);
  
  Future<String> fetchTemperature() async {
    await Future.delayed(Duration(seconds: 1));
    return '22°C in $_location';
  }
  
  Future<void> updateLocation(String newLocation) async {
    await Future.delayed(Duration(milliseconds: 500));
    _location = newLocation;
    print('Location updated to $_location');
  }
}

Future<void> main() async {
  var service = WeatherService('London');
  var temp = await service.fetchTemperature();
  print(temp);
  
  await service.updateLocation('Paris');
}

异步方法可以像普通方法一样访问和修改实例变量。关键区别在于,调用方必须对结果使用 await。返回 Future<void> 的方法不会返回值,但如果你想确保它们完成后再继续,就仍然需要等待它们。

你还可以在一个方法中组合多个异步调用,或者在同一个类中调用其他异步方法:

Future<String> getFullReport() async {
  var temp = await fetchTemperature();
  var humidity = await fetchHumidity();
  return '$temp, Humidity: $humidity';
}

这种模式对于与外部资源交互的类至关重要,例如 API、数据库,或任何需要耗费时间的操作。

challenge icon

挑战

简单

让我们构建一个股票投资组合跟踪器,使用异步方法管理股票价格并计算投资组合价值!你将创建一个类,模拟获取实时股票数据,并组合多个异步操作来生成报告。

你将把代码分成两个文件:

  • portfolio.dart:创建一个用于跟踪股票及其数量的 StockPortfolio 类。这个类应包含:
    • 一个名为 _holdings 的私有 Map<String, int>,用于存储股票代码和持有的股份数量
    • 一个将 _holdings 初始化为空映射的构造函数
    • 一个用于添加或更新股票持仓的方法 addStock(String symbol, int quantity)(非异步)
    • 一个返回 Future<double> 的异步方法 fetchPrice(String symbol)。模拟延迟 50 毫秒,然后返回按以下方式计算的价格:股票代码的长度乘以 25.5
    • 一个返回 Future<double> 的异步方法 getStockValue(String symbol)。此方法应等待该股票代码对应的 fetchPrice,将价格乘以持有数量,并返回总价值。如果持仓中没有该股票代码,则返回 0.0
    • 一个返回 Future<double> 的异步方法 getTotalValue()。此方法应通过等待每只股票对应的 getStockValue 并对结果求和,计算所有持仓的总价值
    • 一个返回 Future<String> 的异步方法 generateReport()。此方法应生成一份报告,显示每只股票的价值和总价值。每行的格式为 [symbol]: $[value](value 保留 1 位小数),最后一行为 Total: $[totalValue](同样保留 1 位小数)
  • main.dart:导入你的投资组合文件,并演示异步方法如何在类中协同工作:
    • 创建一个 StockPortfolio 实例
    • 添加以下持仓:AAPL 10 股,GOOGL 5 股,MSFT 8 股
    • 打印 Fetching portfolio data...
    • 等待并打印 generateReport() 的结果

注意,generateReport() 会在同一个类中调用其他异步方法,而且每个方法都基于其他方法的结果继续完成工作。使用 toStringAsFixed(1) 格式化小数值!

预期输出:

Fetching portfolio data...
AAPL: $1020.0
GOOGL: $637.5
MSFT: $816.0
Total: $2473.5

亲手试试

import 'portfolio.dart';

void main() async {
  // TODO: 创建一个 StockPortfolio 实例

  // TODO: 添加持仓:
  // - AAPL,10 股
  // - GOOGL,5 股
  // - MSFT,8 股

  // TODO: 打印 "Fetching portfolio data..."

  // TODO: 等待并打印 generateReport() 的结果
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器