斯卡拉上下界

时间:2016-10-14 10:14:32

标签: scala generics

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等泛型)

1 个答案:

答案 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]

但是:它真的没有意义恕我直言。