Scala函数接口特质

4

我有一个特性:

trait MyTrait extends (Int => MyTrait)

我如何限制在扩展中使用MyTrait只能是MyTrait的任何实现?
2个回答

9
在Scala中,Function类型被标记为协变,用+R表示在Function1签名中: trait Function1[-T1, +R] extends AnyRef 这意味着你已经是正确的了。将MyTrait扩展为(Int=> MyTrait)(与Function1[Int, MyTrait]相同),这意味着任何扩展MyTrait的类型都必须实现返回任何MyTrait实例的应用函数。
根据您当前MyTrait的签名,以下内容都是合法的:
class Foo extends MyTrait {
    def apply(x: Int): Foo = new Foo
}

class Bar extends MyTrait {
    def apply(x: Int): Foo = new Foo
}

class Baz extends MyTrait {
    def apply(x: Int): MyTrait = new MyTrait { def apply(y: Int) = new Baz }
}

1
感谢@dcastro。回答已更新。总有一天我会弄清协变与逆变的区别。 - Dan Gallagher
3
哈哈,我知道,对吧?这是我记忆它的方式:共变是指两种类型在相同方向上变化:A :> B 因此 X[A] :> X[B]协变是指它们在相反方向上变化:A :> B 因此 X[B] :> X[A](注:在拉丁语和一些派生自拉丁语的语言中,“contra”意为“反对”)。 - dcastro

6

正如Dan所写的那样,普通情况下会返回MyTrait的任何实例。

如果你想限制它只返回当前对象类型的实例,可以这样做:

trait MyTrait[T <: MyTrait[T]] extends (Int => T)

然后当你实现它(从Dan复制)时

class Foo extends MyTrait[Foo] {
    def apply(x: Int): Foo = new Foo
}

class Bar extends MyTrait[Bar] {
    def apply(x: Int): Foo = new Foo //Compile error
}

class Baz extends MyTrait[Baz] {
    def apply(x: Int): MyTrait = new MyTrait { def apply(y: Int) = new Baz }
}

3
这被称为“F-bounded多态性”。 - Daenyth
2
我真的很喜欢这个模式,认为它非常有用。只是一个小提示,我认为 Baz 类也无法编译,因为 apply 必须返回一个 Baz - Dan Gallagher

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