跳到主要内容

Dot shorthands(点号简写)

点号简写允许在上下文已经明确类型时,省略枚举名或类名,把 Type.member 写成 .member。它能减少重复,但不会进行动态查找:编译器必须从表达式所在位置得到足够精确的上下文类型。

版本说明:点号简写从 Dart 3.10 开始可用。使用该语法的 package 需要设置兼容的最低 SDK 约束。

枚举值简写

变量声明已经给出枚举类型时,可以省略枚举名:

enum Status { idle, running, stopped }

void main() {
Status current = .running;
print(current == Status.running); // true
}

这里左侧要求 Status,因此编译器把 .running 解析为 Status.running

点号简写也适用于参数和返回值等具有明确期望类型的位置:

enum Alignment { start, center, end }

void setAlignment(Alignment alignment) {
print(alignment);
}

Alignment defaultAlignment() => .center;

void main() {
setAlignment(.end);
}

调用构造函数

.new() 表示调用上下文类型的无名构造函数,.named() 表示调用命名构造函数:

class Point {
final int x;
final int y;

const Point(this.x, this.y);
const Point.origin() : this(0, 0);
}

void main() {
Point first = .new(2, 3);
Point second = .origin();

print('${first.x}, ${second.y}'); // 2, 0
}

在常量位置,可以把 const 与简写组合:

const Point origin = .origin();

静态成员简写

只要静态成员的结果与上下文类型兼容,也可以省略类型名:

class ThemeMode {
final String name;

const ThemeMode._(this.name);

static const light = ThemeMode._('light');
static const dark = ThemeMode._('dark');
}

void main() {
ThemeMode mode = .dark;
print(mode.name); // dark
}

简写从一个静态成员、构造函数或枚举值开始,之后还可以继续进行成员访问或方法调用。

switch 与集合中的简写

分支结果具有统一上下文类型时,点号简写可以让重复的类型名更少:

enum Result { success, failure }

Result parse(bool valid) => switch (valid) {
true => .success,
false => .failure,
};

void main() {
List<Result> results = [.success, .failure];
print(results);
}

List<Result> 为集合元素提供了 Result 上下文,函数返回类型则为每个 switch 分支提供上下文。

相等比较的特殊规则

==!= 的右侧直接使用点号简写时,左侧表达式的静态类型可作为上下文:

enum Color { red, green, blue }

void main() {
Color color = Color.green;

if (color == .green) {
print('matched');
}
}

这个规则具有方向性,.green == color 不成立,因为简写位于左侧时没有可用的左侧类型。复杂表达式或先把左侧转为 Object,也可能使类型上下文丢失。

什么时候不能使用

var 本身需要从右侧推断类型,因此下面的写法缺少上下文:

enum Status { idle, running }

void main() {
// var status = .running; // 编译错误:无法确定 .running 属于哪个类型
var status = Status.running; // 正确
}

当多个类型都可能满足上下文、期望类型过宽,或成员不属于推断出的类型时,也必须写出完整类型名。公共 API 或较长表达式中,如果简写降低可读性,保留完整名称更合适。

TypeScript 对比:TypeScript 通常需要写出 Status.running,没有与 Dart .running 相同的上下文点号简写。对象字面量的上下文类型推断与此有相似之处,但不能用来省略枚举或类名。

常见误区

  • .member 依赖静态上下文类型,不是运行时按名称搜索成员。
  • var value = .member 通常无法推断,因为左右两侧都没有提供类型。
  • 相等比较只允许右侧简写借用左侧类型,交换两边可能导致编译错误。
  • 简写不意味着成员变成实例成员;它仍然解析为某个类型的静态成员或构造函数。

小结

  • 点号简写在类型已知时把 Type.member 缩短为 .member
  • 它适用于枚举值、静态成员、无名构造函数 .new() 和命名构造函数。
  • 参数、返回值、集合元素和 switch 分支都可能提供上下文类型。
  • ==!= 右侧具有从左侧取得类型的特殊规则。
  • 上下文不明确或可读性下降时,应使用完整类型名。