假设我有
trait A
case class S(s:String) extends A
case class B(b:Boolean) extends A
和
val m = scala.collection.mutable.HashMap[String,(Seq[C]) => Option[A]](
"testS" -> ((cs:Seq[C]) => Some(S(foo(cs)))),
"testB" -> ((cs:Seq[C]) => Some(B(bar(cs)))),
...
)
现在假设我们的D
类型为D <: C
:
val m = scala.collection.mutable.HashMap[String,(Seq[C]) => Option[A]](
"testS" -> ((cs:Seq[C]) => Some(S(foo(cs)))),
"testB" -> ((cs:Seq[C]) => Some(B(bar(cs)))),
"testD" -> ((ds:Seq[D]) => Some(B(baz(ds.head)))), //oops!
...
)
是的,像我一样愚蠢,我再次忘记了论据应该是逆变的,这意味着
D <: C, therefore (C => E) <: (D => E)
当然,Scala不会让我这样做:“类型不匹配”
使用地图的整个想法是客户端应该能够添加自己的映射。当然,我可以简单地要求添加这样的案例,如
"testD" -> ((ds:Seq[C]) => Some(B(baz(ds.head.asInstanceOf[D]))))
但这是唯一的解决方案吗?
答案 0 :(得分:0)
在这里使用asInstanceOf
很危险。如果ds.head
实际上是其他D2
D2 <: C
的实例,该怎么办?这不是一个逆变问题,因为你需要优化你的抽象,以便类型更有意义。
您应该考虑如何使用字典m
- 您是否尝试将其所有值应用于某些通用Seq[C]
?如果是这样,则不应允许客户端传递D => E
类型的函数,因为这些函数可能不适用于C
的所有实例。如果每个客户端都有自己的字典,其中所有方法都有一个类型的参数,那么客户端实例化在某些类型X <: C
中应该是通用的,然后m
可以包含{{1}的方法}}。
当然,需要更多详细信息来提出一个可能在这里工作的类型系统,因为现在你的函数列表的唯一自然类型是X => E
,这是因为它自己的原因是危险的。以下是您的问题的简化版本,可能有助于阐明该问题:
Any => E