Scala中的广义结构类型一致性

Aar*_*rup 5 scala structural-typing

我对将特定类型符合更一般结构类型的问题感兴趣.请考虑以下示例:

trait Sup

trait Sub extends Sup

type General = {
   def contra(o: Sub): Unit
   def co(): Sup
   def defaults(age: Int): Unit
   def defaults2(age: Int): Unit
   def defaults3(first: String): Unit
} 

trait Specific {
   def contra(o: Sup): Unit // doesn't conform
   def co(): Sub // conforms
   def defaults(age: Int, name: String = ""): Unit // doesn't conform
   def defaults2(name: String = "", age: Int = 0): Unit // doesn't conform
   def defaults3(first: String = "", last: String = ""): Unit // doesn't conform
}
Run Code Online (Sandbox Code Playgroud)

在每个不符合的情况下,对方法的调用General可以安全地解析为相应的方法Specific.在这个问题中可以找到一个更有趣的实例:

trait Versionable[T] {
   self: { def copy(version: Int): T } =>
   val version = 0
   def incrementVersion = copy(version = version + 1)
}

case class Customer(name: String, override val version: Int) 
      extends Versionable[Customer] {
   def changeName(newName: String) = copy(name = newName)
}
Run Code Online (Sandbox Code Playgroud)

这里,Customer的copy方法不符合Versionable的自我类型注释中的签名.但是请注意,如果编译器允许,copy可以像调用它一样调用它Versionable.incrementVersion.显然,Customer的copy方法的实际签名对于在Versionable中使用来说太具体了,因为它带有可以选择提供name参数的无关知识.

有办法解决这些限制吗?是否有理由认为这种普遍的一致性是个坏主意?

Mag*_*nus 1

一个问题是,当您阅读这段代码时:

self: { def copy(version: Int): T }
Run Code Online (Sandbox Code Playgroud)

您不希望参数的名称很重要,因为在本例中它必须如此:

case class Robot(number: Int, override val version: Int)
  extends Versionable[Robot]
Run Code Online (Sandbox Code Playgroud)

编辑:另一方面,关于方法缺乏参数逆变,您可以这样做:

type General = { val contra: (Sub => Unit) }
class B { val contra = ((o:Sup) => println(o)) }
var b:General = new B
Run Code Online (Sandbox Code Playgroud)