dart 如何重写抽象类的setter以使值成为final

9rygscc1  于 2023-11-14  发布在  其他
关注(0)|答案(1)|浏览(94)

给定一个abstract class“Foo”,它有一个“值”的getter和setter

abstract class Foo<T> {
  T get value;
  set value(T newValue);
}

字符串
我试图覆盖getter和setter来使值成为final;
通过下面的实现

class Bar implements Foo<String> {
  @override
  final String value;
  const Bar(this.value);
}


短绒器抱怨Missing concrete implementation of 'setter Foo.value'.
但如果我们加上

class Bar implements Foo<String> {
  @override
  final String value;
  const Bar(this.value);
  @override
  set value(String newValue) => value = newValue;
}


当我们使用setter时

void main() {
  const bar = Bar('hello');
  bar.value = 'world';
  print(bar.value);
}


我们没有收到关于使用setter作为最终值的ant警告,但在运行时我们会引发此错误

Uncaught RangeError: Maximum call stack size exceededError: RangeError: Maximum call stack size exceeded


这个问题似乎只针对二传手,因此,

重写抽象类的setter使其值为final的正确方法是什么?

h5qlskok

h5qlskok1#

没有正确的方法来禁用基类中的setter,因为这样做根本上是不正确的。派生类必须可以替换基类。如果派生类没有提供setter,那么它将不再提供基类的接口,并且将违反the substitution principle。考虑:

void updateFoo<T>(Foo<T> foo, T newValue) => foo.value = newValue;

void main() {
  var bar = Bar('hello');
  updateFoo(bar, 'world');
}

字符串
不可能发出任何编译时警告或错误;从静态分析来看,updateFoo的实现和调用都是法律的。
相反,请考虑:

  • 如果可能的话,颠倒类的层次结构:使只读类成为基类,并在派生类中提供setter或mutator。
  • 接受一个什么都不做(尽管调用者可能不会期望这样)或在运行时抛出异常(这就是UnmodifiableListView这样做的事情)的setter。

此外,由于实现中的另一个错误,会发生特定的异常。当您这样做时:

@override
  set value(String newValue) => value = newValue;


那么value = newValue;语句将再次触发value setter *,导致无限递归,正如错误消息所暗示的那样。如果你尝试这样做:

final String _value;

  @override
  String get value => _value;

  @override
  set value(String newValue) => _value = newValue;


那么你的Bar实现会因为试图重新分配_value而产生一个编译时错误,也就是final。如果你让_value成为非final,那么编译器会产生一个编译时错误,告诉你Bar不能有const构造函数。

相关问题