接口扩展

例如下面的例子,类型 Array 本身没有实现接口 PrintSizeable,但可以通过扩展的方式为 Array 增加额外的成员函数 printSize,并实现 PrintSizeable

interface PrintSizeable {
    func printSize(): Unit
}

extend<T> Array<T> <: PrintSizeable {
    public func printSize() {
        println("The size is ${this.size}")
    }
}

当使用扩展为 Array 实现 PrintSizeable 之后,就相当于在 Array 定义时实现接口 PrintSizeable

因此可以将 Array 作为 PrintSizeable 的实现类型来使用了,如以下代码所示。

main() {
    let a: PrintSizeable = Array<Int64>()
    a.printSize() // 0
}

编译执行上述代码,输出结果为:

The size is 0

可以在同一个扩展内同时实现多个接口,多个接口之间使用 & 分开,接口的顺序没有先后关系。

如下面代码所示,可以在扩展中为 Foo 同时实现 I1I2I3

interface I1 {
    func f1(): Unit
}

interface I2 {
    func f2(): Unit
}

interface I3 {
    func f3(): Unit
}

class Foo {}

extend Foo <: I1 & I2 & I3 {
    public func f1(): Unit {}
    public func f2(): Unit {}
    public func f3(): Unit {}
}

也可以在接口扩展中声明额外的泛型约束,来实现一些特定约束下才能满足的接口。

例如可以让上面的 Pair 类型实现 Eq 接口,这样 Pair 自己也能成为一个符合 Eq 约束的类型,如下代码所示。

class Pair<T1, T2> {
    var first: T1
    var second: T2
    public init(a: T1, b: T2) {
        first = a
        second = b
    }
}

interface Eq<T> {
    func equals(other: T): Bool
}

extend<T1, T2> Pair<T1, T2> <: Eq<Pair<T1, T2>> where T1 <: Eq<T1>, T2 <: Eq<T2> {
    public func equals(other: Pair<T1, T2>) {
        first.equals(other.first) && second.equals(other.second)
    }
}

class Foo <: Eq<Foo> {
    public func equals(other: Foo): Bool {
        true
    }
}

main() {
    let a = Pair(Foo(), Foo())
    let b = Pair(Foo(), Foo())
    println(a.equals(b)) // true
}

编译执行上述代码,输出结果为:

true

如果被扩展的类型已经包含接口要求的函数或属性,那么在扩展中不需要并且也不能重新实现这些函数或属性。

例如下面的例子,定义了一个新接口 Sizeable,目的是获得某个类型的 size,而已经知道 Array 中包含了这个函数,因此就可以通过扩展让 Array 实现 Sizeable,而不需要添加额外的函数。

interface Sizeable {
    prop size: Int64
}

extend<T> Array<T> <: Sizeable {}

main() {
    let a: Sizeable = Array<Int64>()
    println(a.size)
}

编译执行上述代码,输出结果为:

0

当多个接口扩展实现的接口存在继承关系时,扩展将按照“先检查实现父接口的扩展,再检查子接口的扩展”的顺序进行检查。

例如,接口 I1 存在一个子接口 I2,且 I1 中包含一个默认实现,类型 A 的两个扩展分别实现了父子接口,根据以上检查顺序,实现 I1 的扩展将会优先检查,然后再检查实现 I2 的扩展。

interface I1 {
    func foo(): Unit { println("I1 foo") }
}
interface I2 <: I1 {
    func foo(): Unit { println("I2 foo") }
}

class A {}

extend A <: I1 {} // first check
extend A <: I2 {} // second check

main() {
    A().foo()
}

编译执行上述代码,输出结果为:

I2 foo

以上例子中,当检查实现 I1 的扩展时,会从 I1 中继承 foo 函数。在检查实现 I2 的扩展时,由于 A 中已存在一个继承的,且签名相同的默认实现 foo ,此时 foo 将被覆盖,因此,调用 Afoo 函数时,最终指向 I2(子接口)中的实现。

如果同一类型的两个接口扩展实现的接口存在继承冲突,导致无法确定检查顺序时,将会报错。

interface I1 {}
interface I2 <: I1 {}
interface I3 {}
interface I4 <: I3 {}

class A {}
extend A <: I1 & I4 {} // error: unable to decide which extension happens first
extend A <: I2 & I3 {} // error: unable to decide which extension happens first

如果同一类型的两个接口扩展实现的接口不存在继承关系,将会被同时检查。

interface I1 {
    func foo() {}
}
interface I2 {
    func foo() {}
}

class A {}
extend A <: I1 {} // Multiple default implementations, need to re-implement 'foo' in 'A'
extend A <: I2 {} // Multiple default implementations, need to re-implement 'foo' in 'A'