2010-08-12 17 views
5

我对将特定类型符合更一般结构类型的问题感兴趣。考虑以下示例: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解析为相应的方法。一个更有趣的实际例子可以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) 
} 

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

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

+0

另一个实际的例子:http://stackoverflow.com/questions/4410469/refactoring-copy-functionality – 2010-12-10 19:48:13

回答

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 
+0

这是一个很好的观点。无论如何,这种广义一致性可能不应该是默认的(出于性能原因)。我认为,在结构类型的'version'参数上需要'@ named'注解可以解决这两个问题。 – 2010-08-31 17:12:04

相关问题