Scala 中的广义结构类型一致性
我对使特定类型符合更通用的结构类型的问题感兴趣。请考虑以下示例:
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
中相应的方法。一个更有趣的实际例子可以在这个问题中找到:
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的自类型注释中的签名。但请注意,如果编译器允许,则可以像在 Versionable.incrementVersion
中一样调用 copy
。显然,客户的 copy
方法的实际签名对于在 Versionable 中使用来说过于具体,因为它携带了可以选择提供 name
参数的不相关知识。
有办法解决这些限制吗?是否有理由认为这种普遍的一致性是一个坏主意?
I'm interested in the problem of conforming a specific type to a more general structural type. Consider the following examples:
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
}
In each of the non-conforming cases, a call to the method in General
can safely be resolved to the corresponding method in Specific
. A more interesting practical example can be found in 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)
}
Here, the Customer's copy
method does not conform to the signature in Versionable's self-type annotation. Note, however, that if the compiler allowed, copy
could be invoked just as it is in Versionable.incrementVersion
. Clearly, the actual signature of Customer's copy
method is too specific for use in Versionable, since it carries the irrelevant knowledge that one can optionally supply a name
parameter.
Are there ways to work around these limitations? Are there reasons that such generalized conformance would be a bad idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一个问题是,当您阅读此代码时:
您不会期望参数名称很重要,因为在本例中它必须如此:
编辑:另一方面,关于缺乏方法的参数逆变,你可以这样做:
One concern is that when you read this code:
you do not expect the name of the parameter to be significant, as it would have to be in this example:
EDIT: On another note, regarding the lack of parameter contravariance for methods, you can do: