scala - 逆变和 val

标签 scala immutability contravariance

“val”和“case”如何以及为何影响类型系统? (特别是方差)

Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class E[-A]
defined class E

scala> class F[-A](val f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
class F[-A](val f: E[A] => Unit)
                       ^  
scala> case class C[-A](f: E[A] => Unit)
<console>:6: error: contravariant type A occurs in covariant position in type => (E[A]) => Unit of value f
   case class C[-A](f: E[A] => Unit)

scala> class F[-A](f: E[A] => Unit)    
defined class F

最佳答案

考虑一下:

trait Equal[-A] { def eq(a1: A, a2: A): Boolean }
val e = new Equal[Option[Int]] { 
    def eq(a1: Option[Int], a2: Option[Int]) = a1 forall (x => a2 forall (x ==)) 
}

// Because Equal is contra-variant, Equal[AnyRef] is a subtype of Equal[String]
// Because T => R is contra-variant in T, Equal[AnyRef] => Unit is a supertype
// of Equal[String] => Unit
// So the follow assignment is valid
val f: Equal[AnyRef] => Unit = (e1: Equal[String]) => println(e1.eq("abc", "def"))


// f(e) doesn't compile because of contra-variance
// as Equal[Option[Int]] is not a subtype of Equal[AnyRef]

// Now let's tell Scala we know what we are doing
class F[-A](val f: Equal[A @uncheckedVariance] => Unit)

// And then let's prove we are not:
// Because F is contra-variant, F[Option[Int]] is a subtype of F[AnyRef]
val g: F[Option[Int]] = new F(f)

// And since g.f is Equal[Option[Int]] => Unit, we can pass e to it.
g.f(e) // compiles, throws exception

如果fF之外不可见,这个问题就不会发生。

关于scala - 逆变和 val,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5097984/

相关文章:

c# - 为什么 ref 参数不是逆变的?

java - 混淆嵌套泛型的集合

scala - 如何将Scala案例类定义转换为Haskell?

scala - toArray 的值不是 org.apache.spark.rdd.RDD[(String, Int)] 的成员

scala 类构造函数参数

c++ - 连接 const_string 的

list - Spark 数据帧值到 Scala 列表

scala - 在 playframework 假应用程序中快速执行测试

functional-programming - 什么是破坏性更新?

c# - 赋值兼容性、逆变和隐式类型转换