为什么Dart的内置List接口可以实例化?

时间:2011-10-11 07:47:58

标签: interface dart

  

注意:这个问题已经过时了;已从Dart中删除interface声明语法:

     

据我所知,在Dart中实例化接口是不可能的。如果我只是尝试构造new MyInterface(),无论是否定义了构造函数,我都会遇到运行时错误(try it):

NoSuchMethodException - receiver: '' function name: 'MyInterface$$Factory' arguments: []]
interface MyInterface {}      
interface MyInterface {
  MyInterface();
}

如果我尝试使用工厂构造函数,返回实现的实例,则会出现编译时错误(try it):

SyntaxError: factory members are not allowed in interfaces
class MyImplementation implements MyInterface {
  MyImplementation();
 }

interface MyInterface {
  factory MyInterface() { return new MyImplementation(); }
}

然而,这似乎与Dart的核心库中的List<E> 1 是接口 2 的现实相矛盾,但它有几个构造函数并且可以被实例化。例如,这工作正常(try it):

main() {
  var list = new List();
  list.add(5);
  print(list.last());
}

为什么List和许多其他内置接口可以实例化?是否有一些方法我错过了或者他们只是作为内置类型接受特殊处理?


1 Dart: Libraries: corelib: interface List<E>
2 “很多Dart核心库都是根据接口定义的。” 3
3 Dart: Tutorial: Interfaces

2 个答案:

答案 0 :(得分:9)

定义接口的语法是:

interfaceDefinition:
    interface identifier typeParameters? superinterfaces? factorySpecification? `{' (interfaceMemberDefinition)* `}'

请注意,factorySpecification必须位于界面正文之前,而不是位于界面之内。

这就是你写它的方式:

interface MyInterface default MyImplementation {

}

class MyImplementation implements MyInterface {
  MyImplementation();
}

或者,如果您想要完整的通用定义:

interface MyInterface<E> default MyImplementation<E> {
    MyInterface(x);
}

class MyImplementation<E> implements MyInterface<E> {
  MyImplementation(this.x);
  E x;
}

修改:有关更完整的示例,您可以在https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/corelib/src/list.dart阅读interface List<E>的源代码,相关的class ListFactory<T>来源位于{{ 3}}

答案 1 :(得分:2)

Dart将factory用于两个不同的事情:factory classes 和factory 构造函数。工厂类看起来像这样:

interface List default ConcreteList {
  List();
  ...
}

class ConcreteList implements List {
  ConcreteList() {}
}

这样做可以让您在界面中定义构造函数。通过执行new List()(或任何接口)调用它们时,它知道实际实例化ConcreteList,因为这是您为该接口指定的工厂类。

这为您提供了一种在接口后面完全封装具体类型的方法,甚至包括构造点。

工厂构造函数如下所示:

class Point {
  static _zero;
  int x, y;

  Point(this.x, this.y) {}

  factory Point.zero() {
    if (_zero == null) _zero = new Point(0, 0);
    return _zero;
  }
}

这里,Point.zero是(命名的)工厂构造函数。工厂构造函数允许您抽象实例化。您像常规构造函数一样调用它们,但它们不会自动生成对象的新实例。相反,你可以自由地在构造函数的主体中做任何你想做的事情。在这里,每次你这样做:

new Point.zero();

您将获得相同的缓存_zero对象,即使您每次都使用new,因为它们的工厂构造函数始终返回相同的对象。它们有几个用途:

  1. 返回以前缓存的对象,就像我们在这里做的那样。
  2. 返回子类。这有点像接口的工厂类。您可以拥有一个可以new的类,但在某些情况下,您可能实际上想要返回它的子类以便专门化它的行为。工厂构造函数允许您在不必更改调用站点的情况下执行此操作。