Dart是否支持运算符重载?

27

我看到Dart不支持函数重载。它是否支持运算符重载?如果支持,能否给我展示一个简单的例子?另外,有哪些优点等相关信息呢?


你在哪里看到Dart不支持函数重载的信息? - AlikElzin-kilaka
例如,@AlikElzin-kilaka在https://dart.dev/guides/language/effective-dart/design#avoid-using-runtime-type-tests-to-fake-overloading中写道。 - Nashev
此外,我们还可以在 https://github.com/dart-lang/sdk/issues/49 上看到讨论(使用类型化参数时支持方法重载)。 - Nashev
6个回答

30

在新版本中使用过载==运算符进行重载时,所选择的答案不再有效。现在需要执行以下操作:

class MyClass {
  @override
  bool operator ==(other) {
    // compare this to other
  }
}

但这样并不安全。other没有被指定为一种类型,可能会发生意想不到的事情。例如:

void main() {
  var a = A(1);
  var b = B(1);
  var result = a == b;
  print(result); //result is true
}

class A {
  A(this.index);

  final int index;

  @override
  bool operator ==(other) => other.index == index;
}

class B {
  B(this.index);

  final int index;
}

那么你可以这样做:

class A {
  A(this.index);

  final int index;

  @override
  bool operator ==(covariant A other) => other.index == index;
}

你需要使用 covariant。因为Object重载了 == 运算符。

或者你可以

测试对象类型:
访问:hash_and_equals

class A {
  A(this.index);

  final int index;

  @override
  bool operator ==(other) => other is A && (other.index == index);

  @override
  int get hashCode => index;
}

4
实际上,我们在这里谈论的是覆盖(overriding),正如 @override 修饰符所示。相比之下,重载(overloading)允许在一个类中多次定义相同的方法或运算符,每次使用不同的签名(即参数列表)。Dart 不支持此功能,但可以使用 dynamic 或命名参数进行模拟。 - Ber
谢谢,@Ber!其中一个例子是类dart.ui.Size,在减号运算符-的情况下,被描述为 OffsetBase operator -(OffsetBase other) { if (other is Size) return Offset(width - other.width, height - other.height); if (other is Offset) return Size(width - other.dx, height - other.dy); throw ArgumentError(other); } 而不是使用两个具有不同输入操作数类型和结果类的运算符- - Nashev
1
在https://dart.dev/guides/language/effective-dart/design#avoid-using-runtime-type-tests-to-fake-overloading页面中,作者强烈建议不要通过封装的运行时类型检查来使用假重载,并指出“Dart没有重载”。 - Nashev

23

Dart支持使用operator关键字和要重载的运算符来进行运算符重载。下面的示例重载了MyClass对象的==运算符:

class MyClass {
  operator ==(MyClass other) {
    // compare this to other
  }
}

几乎所有Dart内置运算符都可以进行重载,但有一些值得注意的例外,其中包括赋值运算符=和引用等价运算符 === (已经不存在)。

至于运算符重载的优点,它允许您重用具有良好语义意义的运算符,例如 == + ,来执行对象的操作。例如,如果您有一个矩阵类,它重载了 + 运算符,则可以使用语法 m1 + m2 添加两个矩阵,而不是使用更麻烦的 m1.plus(m2)。


你能告诉我'other'是否有什么特殊含义,或者它可以被命名为其他名称吗?例如==(MyClass ggg)。 - Muhammad Umer
1
@MuhammadUmer 其他的名称可以是任何东西,它只是你要比较的类对象的参数名称,即 this == other 或 this + other。 - Lars Tackmann
参数必须是相同类型吗?还是可以像Scala的List cons运算符::一样创建运算符,其中左侧的类型是元素类型以创建新头部,右侧的类型是List类型? - pohl
关于重写 == 时需要注意的常见陷阱,请参见 http://work.j832.com/2014/05/equality-and-dart.html。 - Günter Zöchbauer
如何在Dart中重载++--运算符? - Second Person Shooter

8
为了扩展Lars的回答,您还可以使用内联函数语法重载运算符。
class MyClass {
  operator ==(MyClass o) => id == o.id;
}

8

一个很好的例子来学习如何使用运算符重载是用于处理Dart中的复数的类:

import 'dart:core';

class Complex {
  final double real;
  final double imaginary;

  Complex({this.real = 0, this.imaginary = 0});

  Complex.ri(this.real, this.imaginary);

  Complex operator +(Complex b) {
    return Complex(
        real: this.real + b.real, imaginary: this.imaginary + b.imaginary);
  }

  Complex operator -(Complex b) {
    return Complex(
        real: this.real - b.real, imaginary: this.imaginary - b.imaginary);
  }

  Complex operator *(Complex b) {
    return Complex(
        real: this.real * b.real - this.imaginary * b.imaginary,
        imaginary: this.real * b.imaginary + this.imaginary * b.real);
  }

  Complex operator /(Complex b) {
    // https://dev59.com/J53ha4cB1Zd3GeqPTFos#41146661
    var conjugation = b.conjugate();
    var denominatorRes = b * conjugation;

    // denominator has only real part
    var denominator = denominatorRes.real;
    var nominator = this * conjugation;

    return Complex(
        real: nominator.real / denominator,
        imaginary: nominator.imaginary / denominator);
  }

  bool operator ==(b) {
    return b.real == this.real && b.imaginary == this.imaginary;
  }

  @override
  String toString() {
    return 'Complex(real: ${real}, imaginary: ${imaginary})';
  }
}

3
自Dart 2.7版本起,您可以将运算符添加到现有的类中,例如:
extension Contains on String {
  bool operator <<(Pattern other) => contains(other);
  bool operator >>(String other) => other.contains(this);
}

-2

以复数为例,我可以实现“Complex * num”如下:

Complex operator *(dynamic b) {
  if (b is Complex) {
    return Complex( real: ... );
  } else if (b is num) {
    return Complex.ri(real*b, imaginary*b);
  }
}
...

但是如何实现“num * Complex”?这是可能的吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接