Dart 3.0 语法新特性 | 类型修饰符 Class modifiers

6,255 阅读4分钟

在 dart 3.0.0 之后,对类型的修饰符进行了拓展,现在类型的修饰符有:

名称作用
mixin混入类修饰符
sealed密封可枚举的子类型
abstract抽象类修饰符
final一定程度上关闭派生能力
base
interface接口

1. mixin 语法变化

在 dart 3.0.0 之前, 没有构造方法的 class 可以视为 mixin , 下面的代码是允许的:

class A {}

class C with A {}

在 dart 3.0.0 之后, mixin 变严格了,和 class 声明的常规类进行的区分,常规类将不被允许混入:

image.png

想要通过 with 关键字混入 A,需要通过 mixin 声明类:

mixin A {}

class C with A {}

或者通过 mixin 关键字对 class 进行修饰:

mixin class A {}

class C with A {}

也就是说,现在 Dart 中将 混入类常规类 进行了语法级别的区分:

mixin 声明定义了一个混入类,允许被通过 with 混入或 on 继承。
class 声明定义了一个常规类,允许被通过 extends 继承。
mixin class 声明定义了一个既可用作常规类又可用作混入类的类。即允许被通过 with 混入或 on 继承,又允许被通过 extends 继承。

  • 在新语法中只有 常规类 才允许使用 extendswith 子句,混入类不允许使用;
  • 只有 混入类 才允许使用 on 子句,常规类不允许使用。
  • mixin class 含有两者的血脉,所以即无法使用 extendswith 子句,也无法使用 on 子句。

image.png


2. 密封类的支持 sealed

有些类型的子类型集是已知的,可枚举的;比如登陆界面的认证状态 AuthState,有如下三种子状态

  • 认证中 AuthLoading
  • 认证成功 AuthSuccess
  • 认证失败 AuthFailure

这时就可以通过密封类来处理,下面的代码看起来似乎和平台的继承也没什么区别,但密封类有它的特点。

sealed class AuthState{} //创建密封类

class AuthLoading extends AuthState{}

class AuthSuccess extends AuthState{
  final String user;
  final String token;

  AuthSuccess(this.user, this.token);
}

class AuthFailure extends AuthState{
  final String error;
  AuthFailure(this.error);
}

  • sealed 修饰的类自动是抽象类,无法被实例化。

image.png

  • sealed 修饰的类无法在外部被 继承 extended, 实现 implemented, 或 混入 with。

image.png

  • sealed 修饰的类可以被 switch 选择。
    如下所示,根据 AuthState 的不同状态,返回不同的字符串。在实际开发中可以返回不同的组件,在对应的分支中可以访问对应派生类中的字段。比如 AuthSuccess 分支中可以通过 state.user 访问用户名;AuthFailure 分支中可以通过 state.error 访问错误信息:
String buildByAuthState(AuthState state){
  return switch(state){
    AuthLoading()=> 'AuthLoading View',
    AuthSuccess()=> 'AuthSuccess View:${state.user}',
    AuthFailure()=> 'AuthFailure View:${state.error}',
  };
}

sealed 最大的特点是子类型可枚举,所以在编码过程中如果少写一个,编译器就是显示地给出提示。这样可以有效避免漏写的可能,这种从语法层面规避潜藏风险,对代码的健壮性是非常友好的。

image.png


3. final 类型修饰符

final 对类进行修饰,其目的是为了关闭该类的继承体系。如下所示,被 final 修饰的类无法被直接继承;

image.png

从提示中可以看出需要继承自 final 修饰的类,子类需要被 base 、final 或 sealed 修饰:

image.png

另外 final 修饰的类无法在外部进行派生:

image.png

从这两点就不难理解,final 修饰的类可以在一定程度上关闭派生能力。


4. base 和 interface 类修饰符

base 和 interface 在我看来是一对,base 是强调 继承 ; interface 是强调 实现 。两者的的目的是:

限制外部文件对修饰类的派生和实现。

base 修饰的类在外部 允许继承,不允许实现

image.png

interface 修饰的类在外部 不允许继承,允许实现

image.png


俗话说无规矩不成方圆,修饰符就是限制的规则,而接受限制就会享有更长远的利益。比如接受红绿灯的限制,会让整体的交通更加顺畅,减少拥堵,出事的可能性。而不是纠结于我多等了几十秒,不利于一时的享受。限制这是一种大局观,其目的是让整体更加有序。

类型修饰符的增加,可以让类本身多了一些特点,也可以控制类的派生能力,这对于构建大型应用来说是友好的。Kotlin 一直都有 sealed 密封类,这是让我垂涎的语法特性,现在 Dart 终于支持了。