为什么方法定义为“cons [B>:A](v:B)”接受不是A的超类型的类型的参数? [英] Why method defined like "cons[B >: A](v: B)" accepts argument of type which is not supertype of A?

查看:186
本文介绍了为什么方法定义为“cons [B>:A](v:B)”接受不是A的超类型的类型的参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在正在研究scala中的差异,并且我认为我对逆转有了很好的理解。例如,给定 trait List [-A] ,我知道 List [Int] 是一个超类型列表[AnyVal]



但是说我有以下特质:

  trait List [+ A] {
def cons(hd:A):List [A]
}

为什么 cons 参数类型错误?



为什么需要 def cons [B>:A](v:B):List [B]



例如:

  val animal_list:List [Animal] =列表(老虎,狗)

如果我们打电话:

  animal_list.cons(tiger)

Tiger<:Animal ,是不是 cons 遇到问题?由于 B Tiger A 动物和 B>:A 不正确。

解决方案 div>

为什么 cons 的参数类型错误?



 特质列表[+ A] {
def cons(hd :A):List [A]
}

编译器会报错:

协变类型A发生在值为hd

的类型A的逆变位置,因为方法参数计数为逆变位置, code> A
是协变的。



让我们设想这个方法声明将被编译。然后我们可以这样做:

$ $ p $ class ListImpl [A] extends List [A] {
override def cons(hd: A):列表[A] = ???
}

val字符串:List [String] = new ListImpl [String]
val值:List [Any] = strings // OK,因为List [String]< :List [Any](在​​List [A]中,A是协变的)
values.cons(13)// OK(??),因为值的静态类型是List [Any],所以cons的参数应该是任何和13符合类型任何

上面的最后一行真的好吗?我们在 values 上调用 cons values strings 相同, strings 是对象类型为 ListImpl [String] 。因此最后一行中的 cons 调用需要 String 参数,但我们正在传递 Int ,因为的静态类型为 List [Any] Int 符合任何。有什么是绝对错误的 - 哪一行是责怪?答案是: cons 方法声明。为了解决这个问题,我们必须从逆变位置(在 cons 声明中)删除协变类型参数 A 。或者,我们可以使 A 非协变。



另请参阅以下问题:#1 #2

...不包含 cons 碰到问题了吗?



  trait List [+ A] {
def cons [B>:A ](v:B):List [B]
}

val animal_list:List [Animal] = List(tiger,dog)//我们假设List.apply和具体实现列表是在某处定义的。

否, animal_list.cons(tiger)

我假设 Animal 是常见的超类型 Dog Tiger ,并且 dog tiger 分别是 Dog Tiger 的实例。


$ b $ < animal_list.cons(tiger)
调用, A B 类型参数被实例化为 Animal ,所以 cons 方法的形式为:

  def cons [Animal>:Animal](v:Animal):List [Animal] 

code>

动物> ;:动物约束因为:


超类型和子类型关系是自反的,这意味着类型
既是超类型也是自身的子类型。 [信息来源]


cons 的参数是 Tiger ,符合类型 Animal ,所以方法调用是类型正确的。



注意,如果你强制 B 将被实例化为 Tiger ,例如 animal_list.cons [Tiger](tiger) ,那么这个调用将不会是类型正确的,并且你会得到编译器错误。



参见类似的例子这里


I am studying variance in scala right now, and I think I have a good understanding of contravariance. For example given trait List[-A], I know that List[Int] is a supertype of List[AnyVal].

But say that I have the following trait:

trait List[+A] {
  def cons(hd: A): List[A]
}

Why is cons parameter type wrong?

Why it is necessary to have def cons[B >: A](v: B): List[B] ?

For example:

val animal_list: List[Animal] = List(tiger, dog)

if we call:

animal_list.cons(tiger)

since Tiger <: Animal, doesn't cons ran into problem? Since B is Tiger and A is Animal and B >: A is not true.

解决方案

Why is cons's parameter type wrong?

trait List[+A] {
  def cons(hd: A): List[A]
}

Compiler give you error:
covariant type A occurs in contravariant position in type A of value hd
because method parameters count as contravariant positions, but A is covariant.

Let's imagine that this method declaration would compile. Then we could do:

class ListImpl[A] extends List[A] {
  override def cons(hd: A): List[A] = ???
}

val strings: List[String] = new ListImpl[String]
val values: List[Any] = strings // OK, since List[String] <: List[Any] (in List[A], A is covariant)
values.cons(13) // OK(??), since values's static type is List[Any], so argument of cons should be Any, and 13 conforms to type Any

Is the last line above really OK? We are calling cons on values. values is the same as strings, and strings is object of type ListImpl[String]. So cons invocation in the last line is expecting String argument, but we are passing Int, because values's static type is List[Any] and Int conforms to Any. Something is definitely wrong here - which line is to blame? The answer is: cons method declaration. To fix this issue, we have to remove covariant type parameter A from contravariant position (in cons declaration). Alternatively we can make A non-covariant.

See also these questions: #1, #2.

... doesn't cons ran into problem?

trait List[+A] {
  def cons[B >: A](v: B): List[B]
}

val animal_list: List[Animal] = List(tiger, dog)  // We are assuming that List.apply and concrete implementation of List is somewhere defined.

No, animal_list.cons(tiger) invocation is type-correct.

I assume that Animal is common supertype of Dog and Tiger, and that dog and tiger are instances of Dog and Tiger respectively.

In animal_list.cons(tiger) invocation, both A and B type parameters are instantiated to Animal, so cons method takes form of:

def cons[Animal >: Animal](v: Animal): List[Animal]

Animal >: Animal constraint is satisfied because:

Supertype and subtype relationships are reflexive, which means a type is both a supertype and a subtype of itself. [source]

The argument to cons is Tiger which conforms to type Animal, so the method invocation is type-correct.

Notice that if you force B to be instantiated to Tiger, like animal_list.cons[Tiger](tiger), then this invocation won't be type-correct, and you'll get compiler error.

See similar example here.

这篇关于为什么方法定义为“cons [B&gt;:A](v:B)”接受不是A的超类型的类型的参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆