【问题标题】:Generalized structural type conformance in ScalaScala 中的广义结构类型一致性
【发布时间】:2011-03-29 03:41:59
【问题描述】:

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

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
}

在每种不符合的情况下,对General 中的方法的调用可以安全地解析为Specific 中的相应方法。更有趣的实际例子可以在this question找到:

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

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

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

【问题讨论】:

标签: scala structural-typing


【解决方案1】:

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

self: { def copy(version: Int): T }

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

case class Robot(number: Int, override val version: Int)
  extends Versionable[Robot]

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

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

【讨论】:

  • 这很好。这种通用的一致性可能无论如何都不应该是默认的(出于性能原因)。我认为,在结构类型中的 version 参数上要求 @named 注释可以解决这两个问题。
猜你喜欢
  • 1970-01-01
  • 2013-07-19
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多