class Queue[+T](
private val leading: List[T],
private val trailing: List[T]
) {
def append[U >: T](x: U) =
new Queue[U](leading, x :: trailing) // ...
}
class Fruit
class oranges extends Fruit
class apple extends Fruit
class diffAppale
val q1: Queue[Fruit] = new Queue[apple](List(new apple), List())
//> q1 : Test.Queue[Test.Fruit] = Test$Queue@30c7da1e
q1.append(new Fruit)
//> res0: Test.Queue[Test.Fruit] = Test$Queue@506e6d5e
q1.append(new oranges)
//> res1: Test.Queue[Test.Fruit] = Test$Queue@96532d6
q1.append(new diffAppale) // i want to restrict this
//> res2: Test.Queue[Object] = Test$Queue@3796751b
在这里我可以添加追加函数我能做什么,我可以看到结果类型被降级为最小公分母
但是我想和java有相同的行为,比如def append [? super T](x:U)//这里追加函数会占用T的超类型的所有对象,如何在scala中实现类似的(实现超级和扩展为java等泛型)
答案 0 :(得分:1)
我不明白为什么要限制这个或为什么返回一个更通用的新不可变对象会给你带来麻烦。
但如果你不想要这种差异,只需删除所有方差注释:
class Queue[A](leading: List[A], trailing: List[A]) {
def append(x: A) = new Queue[A](leading, x :: trailing) // ...
}
class Fruit
class Orange extends Fruit
class Apple extends Fruit
class NotFruit
val q1: Queue[Fruit] = new Queue(List(new Apple), Nil)
val q2 = q1.append(new Fruit) // ok
val q3 = q2.append(new Orange) // ok
q1.append(new NotFruit) // error - found NotFruit, required Fruit
至于问题:
append函数将获取T
的超类型的所有对象
这是您的原始代码已经执行的操作。请注意,Any
是所有类型的超类型。由于参数处于协变位置,因此始终可以为期望类型 Any
的参数传递子类型为Any
的值。这就是生活:) Scala感觉与Java不同,因为它是围绕声明站点差异而不是使用站点差异(可以说是比Java的泛型更好的决策)。
如果您需要进一步的约束,可以要求提供证据参数,例如
def append[B >: A](x: B)(implicit ev: B <:< Seedless): Queue[B]
或者设置上限(由于A
的差异,这不能与A
相同):
def append[B >: A <: Fruit](x: B): Queue[B]
但是:它真的没有意义恕我直言。