Dart 中内置类型的重载运算符

Overload Operator for Built-in Type in Dart

考虑以下 Dart 代码:

class Vec2 {
  num x, y;
  Vec2(this.x, this.y);
  Vec2 operator*(num rhs) => Vec2(x * rhs, y * rhs);
  String toString() => "<$x, $y>";
}

void main() => print(Vec2(1, 2) * 3);

输出符合预期:

<3, 6>

但是,这仅在表达式左侧为 Vec2 且右侧为 num 时有效。在这种情况下,我希望乘法运算符是可交换的,所以我写了以下扩展:

extension Vec2Util on num {
  Vec2 operator*(Vec2 rhs) => Vec2(rhs.x * this, rhs.y * this);
}

人们自然会期望以下代码产生与第一个片段相同的输出:

void main() {
  num x = 3;
  print("${x * Vec2(1, 2)}");
}

但是,编译器反而报告 The argument type 'Vec2' can't be assigned to the parameter type 'num'. 在这种情况下,编译器似乎正在将乘法解析为 num operator*(num rhs),然后抱怨我的 Vec2 不能作为 num 操作数传入。为什么编译器显然无视我的扩展?创建这样的自定义交换运算符的正确方法是什么?

你不能为所欲为。

Dart user-definable 二元运算符都是第一个操作数上的方法。做 e1 + e2kind-of 就像 e1.+(e2) 其中 + 是方法的名称,除了你不能正常调用方法 +.

为了能够做到 3 * vector,您需要在 3.

上使用该方法

您不能将方法添加到其他人的 class 中,除非不修改他们的源代码,而且 int 是一个系统 class,所以即使那样也是不可能的。

您不能使用扩展方法,因为当接收器类型已经具有同名的实例方法时,扩展方法不适用。 并且 int 定义了 所有 运算符。 (这就像 user-definable 运算符正是从 int 的需要中选择的,这绝对不是巧合。这在 Dart 中并不新鲜,运算符回到 C 和 Java。)

所以,你可以在 int 上定义一个扩展方法,但无论如何你都不能调用它,不是没有覆盖:

extension MyInt on int {
  Vector operator *(Vector other) => other.scalerMultiplication(this);
}
... MyInt(3) * vector ...

这比交换操作数 更复杂。