根据this article,在Dart中,可以将非抽象类定义为具有抽象(或未实现)的方法。 抽象方法会引发警告,但不会阻止实例化。
允许在Dart中的非抽象(或具体)类中声明抽象方法的目的是什么? Dart为什么设计以这种方式工作?
答案 0 :(得分:2)
specification实际上非常明确地声明了具体类中的抽象方法:
如果抽象成员m 声明或在具体类中继承
,则它是静态警告如果声明具有抽象成员的具体类,我们希望警告。
如果具体类具有抽象成员(声明或继承),则它是静态警告。
他们没有任何预期目的,这就是他们发出警告的原因。如果您熟悉Java:它与accessing a static member via an object类似,这也毫无意义并触发警告。
至于为什么它通过编译,Dart使用optional type system,这意味着键入概念不应该影响语言的语义,而这正是Dart强制执行的:
抽象方法的目的是为类型检查和反射等目的提供声明。
静态检查程序将报告一些违反类型规则的行为,但此类违规行为不会中止编译或妨碍执行。
答案 1 :(得分:0)
具体类中的抽象方法允许您为通过noSuchMethod()
实现的方法提供类型签名。提供noSuchMethod()
实施也会使警告无效。
在强模式下,只是在具体类中使用抽象方法将导致错误,除非该类还实现了noSuchMethod()
接口。
简而言之,具体类中抽象方法的目的是为noSuchMethod()
实现提供类型签名。这样可以避免调用未知方法和强模式的警告(这是dartdevc
的默认设置,并且首先是默认值,然后是Dart 2.0的必需项)这些类型签名对于noSuchMethod()
的代码是必需的甚至编译,除非目标是dynamic
类型。
示例:
class A {
void f();
dynamic noSuchMethod(Invocation inv) => null;
}
void main() {
var a = new A();
a.f();
}
如果我们用(例如)a.f()
替换a.f(0)
,那么这将导致使用错误数量的参数调用方法时出现错误(在强模式下)。如果我们省略void f()
声明,那么我们会收到A
没有方法f()
的错误。如果我们省略noSuchMethod()
实施,则投诉将是f()
缺少方法正文,即使A
不抽象。
以下代码提供了一个更现实的示例:
import "dart:mirrors";
class DebugList<T> implements List<T> {
List<T> _delegate;
InstanceMirror _mirror;
DebugList(this._delegate) {
_mirror = reflect(_delegate);
}
dynamic noSuchMethod(Invocation inv) {
print("entering ${inv.memberName}");
var result = _mirror.delegate(inv);
print("leaving ${inv.memberName}");
return result;
}
}
void main() {
List<int> list = new DebugList<int>([1, 2, 3]);
int len = list.length;
for (int i = 0; i < len; i++) print(list[i]);
}
此示例为List<T>
创建调试装饰器,显示所有方法调用。我们使用implements List<T>
来引入整个列表界面,继承了许多抽象方法。这通常会在dartanalyzer
运行时导致警告(或强模式,错误),因为我们缺少List<T>
通常提供的所有这些方法的实现。提供noSuchMethod()
实现会使这些警告/错误无效。
虽然我们也可以手动包装所有50多种方法,但这将是很多打字。如果将新方法添加到列表界面而不必更改我们的代码,上述方法也将继续有效。
用于在具体类中显式列出方法的用例不太常见,但也可能发生。一个例子是在这样的调试装饰器中添加getter或setter,允许我们检查或设置委托的实例变量。无论如何,我们需要将它们添加到界面中,以避免使用它们时出现警告和错误;然后,noSuchMethod()
实施可以使用getField()
和setField()
来实现它们。这是前一个示例的变体,使用堆栈而不是列表:
// main.dart
import "dart:mirrors";
import "stack.dart";
class DebugStack<T> implements Stack<T> {
Stack<T> _delegate;
InstanceMirror _mirror;
DebugStack(this._delegate) {
_mirror = reflect(_delegate);
}
dynamic _get(Symbol sym) {
// some magic so that we can retrieve private fields
var name = MirrorSystem.getName(sym);
var sym2 = MirrorSystem.getSymbol(name, _mirror.type.owner);
return _mirror.getField(sym2).reflectee;
}
List<T> get _data;
dynamic noSuchMethod(Invocation inv) {
dynamic result;
print("entering ${inv.memberName}");
if (inv.isGetter)
result = _get(inv.memberName);
else
result = _mirror.delegate(inv);
print("leaving ${inv.memberName}");
return result;
}
}
void main() {
var stack = new DebugStack<int>(new Stack<int>.from([1, 2, 3]));
print(stack._data);
while (!stack.isEmpty) {
print(stack.pop());
}
}
// stack.dart
class Stack<T> {
List<T> _data = [];
Stack.empty();
Stack.from(Iterable<T> src) {
_data.addAll(src);
}
void push(T item) => _data.add(item);
T pop() => _data.removeLast();
bool get isEmpty => _data.length == 0;
}
请注意,_data
getter的抽象声明对于类型检查至关重要。如果我们要删除它,即使没有强模式我们也会收到警告,并且在强模式下(例如,使用dartdevc
或dartanalyzer --strong
),它会失败:
$ dartdevc -o main.js main.dart
[error] The getter '_data' isn't defined for the class 'DebugStack<int>' (main.dart, line 36, col 15)
Please fix all errors before compiling (warnings are okay).