【问题标题】:Scala - mapping to functions, struggling against contravarianceScala - 映射到函数,对抗逆变
【发布时间】:2015-07-11 07:12:56
【问题描述】:

假设我有

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]))))

但这是唯一的解决方案吗?

【问题讨论】:

    标签: scala dictionary covariance contravariance


    【解决方案1】:

    您对asInstanceOf 的使用在这里很危险。如果ds.head 实际上是其他D2 &lt;: CD2 的一个实例呢?这不是逆变的问题,因为您需要改进抽象以使类型更有意义。

    您应该考虑如何使用您的字典m——您是否尝试将其所有值应用于一些通用的Seq[C]?如果是这样,则不应允许客户端传入D =&gt; E 类型的函数,因为这些函数可能不适用于C 的所有实例。如果每个客户端都有自己的字典,其中所有方法都有单一类型的参数,那么客户端实例化可能应该是某种类型的泛型X &lt;: C,然后m 可以包含来自X =&gt; E 的方法。

    当然需要更多的细节来提出一个可能在这里工作的类型系统,因为现在你的函数列表的唯一自然类型是Any =&gt; E,它本身就很危险。以下是您的问题的简化版本,可能有助于阐明问题:

    import scala.collection.mutable._
    trait C
    trait D extends C
    val cfunc: C => Int = c => 1
    val dfunc: D => Int = d => 1
    var list = ListBuffer[C => Int](cfunc)
    list += dfunc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2020-05-27
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多