Dart 3 新特性 switch
Dart 3被描述为迄今为止最大的Dart版本。
这个版本引入了一些重要的特性,例如:
- 模式和记录
- 增强的switch和if-case语句
- 解构
- 封闭类和其他类修饰符
这些特性在Flutter Forward首次宣布,并我很高兴现在可以在Flutter 3.10和Dart 3.0正式发布后使用它们。
实际上,Dart 3.0允许我们编写更具表现力和优雅的代码,但如果想充分利用它,会有一些学习曲线。
由于需要涵盖的内容很多,我决定写一系列新文章,详细介绍如何使用每个特性,以及您在现实世界中可能遇到的示例和实际用例。
至于本文,我想为您展示一些Dart 3.0提供的特点。
换句话说,这篇文章是前菜。接下来的将是主菜(和甜点 🍰)。
准备好了吗?让我们开始吧!
在您的Flutter项目中启用Dart 3
要使用这些新特性,您需要在您的pubspec.yaml
文件中启用Dart 3.0:
environment:
sdk: '>=3.0.0 <4.0.0'
在创建一个新的Flutter 3.10项目时,默认启用Dart 3.0。
有了这个设置,让我们来了解一下新的语言特性。🔥
Dart 3中的Records简介
Records非常灵活,可以在许多不同的场景中使用。
举个例子,想象一下,你正在进行网络请求并获得一些JSON数据,它看起来像这样:
final json = {'name': 'Andrea', 'age': 38, 'height': 184};
如果您直接使用 json
变量,Dart 会将其推断为 Map
,从而失去类型安全性。
为了改进这一点,您可以声明一个 Person
类,并在一个工厂构造函数内实现反序列化逻辑:
class Person {
const Person({required this.name, required this.age, required this.height});
final String name;
final int age;
final int height;
factory Person.fromJson(Map<String, dynamic> json) {
// * error handling code missing for simplicity
return Person(
name: json['name'],
age: json['age'],
data-height: json['height'],
);
}
}
(String, int, int) getPerson(Map<String, dynamic> json) {
return (
json['name'],
json['age'],
json['height'],
);
}
final person = getPerson(json);
print(person.$1); // 'Andrea'
print(person.$2); // 38
print(person.$3); // 184
或者,您可以像这样解构返回的值:
final (name, age, height) = getPerson(json);
print(name); // 'Andrea'
print(age); // 38
print(height); // 184
但还有更多。👇
位置参数与命名参数
在上面的示例中,记录类型仅使用了位置参数(在其他编程语言中,这被称为元组)。
但 Dart 记录也可以使用命名参数。
这意味着如果我们希望,我们可以更改函数的返回类型:
// same example as above, now using named arguments
({String name, int age, int height}) getPerson(Map<String, dynamic> json) {
return (
name: json['name'],
age: json['age'],
data-height: json['height'],
);
}
因此,我们可以像这样获取和打印记录的数值:
final person = getPerson(json);
print(person.name); // 'Andrea'
print(person.age); // 38
print(person.height); // 184
// * we'll cover the : syntax in a follow up article
final (:name, :age, :height) = getPerson(json);
print(name); // 'Andrea'
print(age); // 38
print(height); // 184
总体来说,可以将记录视为类的轻量级替代品。
与Map
或List
相比,记录更加类型安全,因为它们允许您指定值的数量以及它们的类型。
它们支持命名参数和位置参数(或二者的组合),就像常规函数参数一样。
正如我们所见,您可以使用解构来进一步简化您的代码。
但如果您想要正确使用记录并避免语法错误,需要遵循一些规则。因此,我将在即将发布的文章中更详细地介绍它们。
引介:Switch 表达式和模式
假设我们正在编写一个二维游戏,玩家可以向上、向下、向左和向右移动。
这可以很容易地表示为一个枚举:
enum Move { up, down, left, right }
现在,假设我们想根据当前的移动来计算特定的偏移量(作为一对x-y坐标)。在Dart 3之前,我们可能会像这样实现所需的代码:
enum Move {
up,
down,
left,
right;
Offset get offset {
switch (this) {
case up:
return const Offset(0.0, 1.0);
case down:
return const Offset(0.0, -1.0);
case left:
return const Offset(-1.0, 0.0);
case right:
return const Offset(1.0, 0.0);
}
}
}
enum Move {
up,
down,
left,
right;
Offset get offset => switch (this) {
up => const Offset(0.0, 1.0),
down => const Offset(0.0, -1.0),
left => const Offset(-1.0, 0.0),
right => const Offset(1.0, 0.0),
};
}
只想在X轴上进行移动吗?那么可以在switch
语句内使用逻辑运算符来利用模式匹配:
double get xAxisMovement => switch (this) {
up || down => 0.0, // logical OR operator with pattern matching
left => -1.0,
right => 1.0,
};
Dart 3的switch表达式功能更加强大。
因此,我将在另一篇文章中详细介绍它们。👍
介绍封闭类
封闭类有助于您检查穷尽性,以便您可以处理所有可能的情况。
在处理代码中的异常时,这特别重要。
例如,您可以使用封闭类来定义后端可能返回的所有可能的身份验证异常:
sealed class AuthException implements Exception {}
class EmailAlreadyInUseException extends AuthException {
EmailAlreadyInUseException(this.email);
final String email;
}
class WeakPasswordException extends AuthException {}
class WrongPasswordException extends AuthException {}
class UserNotFoundException extends AuthException {}
这让你可以使用 switch 表达式处理每种可能的异常类型:
String describe(AuthException exception) {
return switch (exception) {
EmailAlreadyInUseException(email: final email) =>
'Email already in use: $email',
WeakPasswordException() => 'Password is too weak',
WrongPasswordException() => 'Wrong password',
UserNotFoundException() => 'User not found',
};
}
以上的代码之所以有效,是因为AuthException
类被声明为sealed
。
如果没有这个声明,我们将会得到一个non_exhaustive_switch_expression
错误:
如果基类没有被声明为sealed
,使用switch表达式时将会产生non_exhaustive_switch_expression
错误。但如果我们将基类标记为sealed
,编译器就会知道我们已经处理了所有可能的情况。
声明一个sealed
类有两个重要的含义:
- 该类变为抽象类(无法创建具体实例)
- 所有的子类必须在同一个库(文件)中定义。
关于sealed
类还有更多内容,敬请期待更深入的文章。😊
Dart 3中的类修饰符简介
在Dart 3之前,只有两个类修饰符可用:abstract
和mixin
。
但在新版本中,我们有六个:
abstract
(抽象)base
(基类)final
(最终)interface
(接口)sealed
(密封)mixin
(混入)
方便的是,Dart官网有一个新页面解释了所有这些修饰符的工作原理:
我可能会在将来更详细地介绍这些修饰符,但目前来说,官方页面是一个很好的起点。
Dart 3: 下一步
通过这篇文章,我希望为您展示了在Dart 3中可以做些什么。
希望我的介绍能激发您尝试在项目中使用这些新语言特性的兴趣。
但还有很多需要探讨的内容,包括if-case
语句、如何对可空值进行模式匹配以及其他高级用法。除非您深刻理解它们的工作原理,否则可能会遇到困难。