但是说我有以下特点:
trait List[+A] { def cons(hd: A): List[A] }
为什么cons参数类型错误?
为什么有必要有缺点[B>:A](v:B):列出[B]?
例如:
val animal_list: List[Animal] = List(tiger,dog)
如果我们打电话:
animal_list.cons(tiger)
既然老虎< ;:动物,没有弊端?由于B是Tiger而A是Animal而B>:A不是真的.
解决方法
trait List[+A] { def cons(hd: A): List[A] }
编译器给你错误:
协变类型A出现在值hd的类型A中的逆变位置
因为方法参数计为逆变位置,但A是协变的.
让我们假设这个方法声明会编译.然后我们可以这样做:
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
上面的最后一行真的好吗?我们在价值观上称之为利弊. values与字符串相同,字符串是ListImpl [String]类型的对象.因此,最后一行中的cons调用期望String参数,但我们传递Int,因为值的静态类型是List [Any],Int符合Any.这里肯定是错的 – 哪条线应该受到责备?答案是:cons方法声明.要解决这个问题,我们必须从逆变位置(在cons声明中)中删除协变类型参数A.或者,我们可以使A非协变.
……没有弊端?
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.
不,animal_list.cons(tiger)调用是类型正确的.
我认为动物是狗和虎的常见超类型,而狗和虎分别是狗和虎的实例.
在animal_list.cons(tiger)调用中,A和B类型参数都被实例化为Animal,因此cons方法采用以下形式:
def cons[Animal >: Animal](v: Animal): List[Animal]
动物>:满足动物约束,因为:
Supertype and subtype relationships are reflexive,which means a type
is both a supertype and a subtype of itself. [07002]
cons的论点是Tiger,它符合类型Animal,因此方法调用是类型正确的.
请注意,如果强制将B实例化为Tiger,例如animal_list.cons [Tiger](tiger),则此调用将不是类型正确的,并且您将收到编译器错误.
见类似的例子here.