Ben*_*itz 13 scala type-inference path-dependent-type type-projection
我想将一个对象传递给一个接受带有投影类型的参数的函数,并让Scala推断出该对象的类型来自包含它的对象.这里有一些简单的代码来说明难度:
trait Cult { cult_ =>
case class CultLeader(personality: Personality) {
val cult = cult_
val follower = personality.attractFollower(this)
}
case class Follower(leader: CultLeader, name: String)
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) =
leader.cult.Follower(leader, "Fred") <-- THIS LINE FAILS TO COMPILE
}
Run Code Online (Sandbox Code Playgroud)
换句话说,CultLeader的Personality应该吸引追随者到与CultLeader相同的邪教.
Scala 2.11.2编译器说:
TypeProjection.scala:11: error: type mismatch;
found : Cult#CultLeader
required: leader.cult.CultLeader
leader.cult.Follower(leader, "Fred")
^
Run Code Online (Sandbox Code Playgroud)
如果我添加一个强制转换,它会正确编译并运行,如下所示:
leader.cult.Follower(leader.asInstanceOf[leader.cult.CultLeader], "Fred")
Run Code Online (Sandbox Code Playgroud)
这似乎很笨拙,它引入了运行时检查,以便在编译时可以推导出来.至少我有一个解决方法.我怎样才能让Scala编译器推断出它leader的类型实际上是leader.cult.CultLeader什么?
我宁愿不cult作为另一个论点传递给attractFollower.在我的实际代码中,这可能会导致很多丑陋的传递cult参数 - 当它真的不需要传递时.
简单的方法是:
trait Cult { cult_ =>
case class CultLeader(personality: Personality) {
val cult = cult_
val follower = personality.attractFollower(this)
}
case class Follower(leader: Cult#CultLeader, name: String) // <-- Cult#CultLeader here
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) =
leader.cult.Follower(leader, "Fred")
}
// Exiting paste mode, now interpreting.
defined trait Cult
defined trait Personality
Run Code Online (Sandbox Code Playgroud)
在这里,您明确指出Follower可以进行任何投影,您实际上试图强制使用asInstanceOf.
还有另一种方法:
trait Cult {
case class CultLeader(personality: Personality) {
def fl(name: String) = Follower(this, name)
val follower = personality.attractFollower(this)
}
case class Follower(leader: CultLeader, name: String)
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) = leader.fl("Fred")
}
Run Code Online (Sandbox Code Playgroud)
要么
trait Cult {
case class CultLeader(personality: Personality) { ld =>
val follower = personality.attractFollower(this)
case class Follower(name: String) { val leader = ld }
}
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) = leader.Follower("Fred")
}
Run Code Online (Sandbox Code Playgroud)
更新:此示例可以更清楚地说明为什么Scala正在做她正在做的事情:
trait Cult { cult_ =>
case class CultLeader(personality: Personality) {
val cult: Cult = cult_ //could be new Cult{} as well
val l = this.asInstanceOf[cult.CultLeader] //We have to do asInstanceOf here because Scala have no glue (from type signature) that this cult is same as cult_
val follower = personality.attractFollower(this)
}
case class Follower(leader: CultLeader, name: String)
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) =
leader.cult.Follower(leader.l, "Fred")
}
// Exiting paste mode, now interpreting.
defined trait Cult
defined trait Personality
Run Code Online (Sandbox Code Playgroud)
这是最终的解决方案,以正确的方式做你想要的:
trait Cult { cult_ =>
case class CultLeader(personality: Personality) {
val cult: cult_.type = cult_
val l: cult.CultLeader = this
val follower = personality.attractFollower(this)
}
case class Follower(leader: CultLeader, name: String)
}
trait Personality {
def attractFollower(leader: Cult#CultLeader) =
leader.cult.Follower(leader.l, "Fred")
}
// Exiting paste mode, now interpreting.
defined trait Cult
defined trait Personality
Run Code Online (Sandbox Code Playgroud)
这里的问题cult_.type是路径依赖(预测).
| 归档时间: |
|
| 查看次数: |
384 次 |
| 最近记录: |