scala下界和上界

scala下界和上界,scala,generics,Scala,Generics,在这里,我可以向append函数添加任何我可以添加的对象,我可以看到结果类型被降级为最低公分母 但我希望具有与java相同的行为,比如def append[?super T](x:U)//这里append函数将接受T的超类型的所有对象,我如何在scala中实现类似的行为(实现super并扩展java之类的泛型)我不明白为什么要限制此操作,或者为什么返回更通用的新不可变对象会给您带来问题 但如果您不希望出现这种差异,只需删除所有差异注释: class Queue[+T]( private

在这里,我可以向append函数添加任何我可以添加的对象,我可以看到结果类型被降级为最低公分母


但我希望具有与java相同的行为,比如def append[?super T](x:U)//这里append函数将接受T的超类型的所有对象,我如何在scala中实现类似的行为(实现super并扩展java之类的泛型)

我不明白为什么要限制此操作,或者为什么返回更通用的新不可变对象会给您带来问题

但如果您不希望出现这种差异,只需删除所有差异注释:

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

关于这个问题:

append函数将获取T的超类型的所有对象

这是您的原始代码已经完成的工作。请注意,
Any
是所有类型的超级类型。由于参数处于协变位置,因此对于预期类型为
Any
的参数,始终可以传递子类型为
Any
的值。这就是生活:)Scala感觉与Java不同,因为它是围绕声明站点差异构建的,而不是使用站点差异(可以说是比Java的泛型更好的决定)

如果需要进一步的约束,可以请求证据参数,例如

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函数添加一些特定的对象类型,它可以由>:,控制,我想你正在尝试考虑需要的更复杂的对象类型。如果您在特定情况下所需的返回类型为
Queue[Fruit]
,它将无论如何不允许您返回
Queue[Any]
。大多数时候,当程序正确地进行类型检查时,人为地强制附加类型约束是没有意义的。无论如何,正如我在回答中所建议的,如果你真的想这样做,只需删除方差。现在我有点困惑:),你已经删除了A(+A)的覆盖率,但是你仍然可以将队列[苹果]添加到队列[水果]中,如下所示val q1:Queue[水果]=新队列(列表(新苹果),Nil)但是如果coverience被删除,我不能添加如下内容:Queue[Fruit]=new Queue[apple](List(new apple),List()),有什么区别@Sharathcandra Scala(与Java类似)是一种具有子类型的语言。
A
类型的参数总是可以通过传递
B类型的值来满足,因为现在A
Queue[Apple]
不再是
Queue[four]
的子类型,所以您不能在没有方差注释的情况下写入
valq1:Queue[four]=new Queue[Apple](List(new Apple),Nil)
。您可以构造一个
val q1:Queue[Fruit]=new Queue[Fruit](List(new Apple),Nil)
,因为
List[+a]
在其元素类型中是协变的,因此,根据经验法则,如果类型参数的使用允许,可以使用方差注释。Scala是一种具有子类型和支持不可变数据类型的语言,使用方差注释使其使用更加顺畅。不要担心返回类型可能会被“加宽”,例如到
队列[Any]
,因为在下一步中,您将看到您可能不会使用这种类型做任何事情。
def append[B >: A](x: B)(implicit ev: B <:< Seedless): Queue[B]
def append[B >: A <: Fruit](x: B): Queue[B]