Rex*_*err 15 collections scala scala-2.8 higher-kinded-types enrich-my-library
假设有人想建立一个新的通用类,Novel[A].这个类将包含许多有用的方法 - 也许它是一种集合 - 因此你想要将它子类化.但是您希望方法返回子类的类型,而不是原始类型.在Scala 2.8中,为了使该类的方法返回相关的子类而不是原始类,必须做的最小工作量是多少?例如,
class Novel[A] /* What goes here? */ {
/* Must you have stuff here? */
def reverse/* What goes here instead of :Novel[A]? */ = //...
def revrev/*?*/ = reverse.reverse
}
class ShortStory[A] extends Novel[A] /* What goes here? */ {
override def reverse: /*?*/ = //...
}
val ss = new ShortStory[String]
val ss2 = ss.revrev // Type had better be ShortStory[String], not Novel[String]
Run Code Online (Sandbox Code Playgroud)
如果你想要Novel协变,这个最小量会改变吗?
(2.8这些集合除了其他内容之外还会执行此操作,但它们也会以更加花哨(和有用)的方式使用返回类型 - 问题是如果一个人只想要这个子类型 - 总是返回子类型,那么很少有框架可以逃脱特征.)
编辑:假设在上面的代码中reverse进行复制.如果一个人进行就地修改然后返回自己,可以使用this.type,但这不起作用,因为副本不是this.
Arjan链接到另一个提出以下解决方案的问题:
def reverse: this.type = {
/*creation of new object*/.asInstanceOf[this.type]
}
Run Code Online (Sandbox Code Playgroud)
这基本上属于类型系统,以获得我们想要的东西.但是,这是不是一个真正的解决方案,因为现在我们已经骗类型系统,编译器不能帮助我们确保我们真正做到让一个ShortStory回来的时候,我们认为我们做的.(例如,我们不必reverse在上面的示例中覆盖以使编译器满意,但我们的类型将不是我们想要的.)
编辑:我刚才意识到雷克斯在他的例子中有一个具体的小说,而不是我在下面使用过的特质.因此,特征实现有点过于简单,无法解决Rex的问题.它也可以使用一个具体的类来完成(见下文),但是我能够做到这一点的唯一方法是通过一些转换,这使得这不是'编译时类型安全'.这样就没有资格作为解决方案.
也许不是最漂亮的,但使用抽象成员类型的简单示例可以实现如下:
trait Novel[A] {
type T <: Novel[A]
def reverse : T
def revrev : T#T = reverse.reverse
}
class ShortStory[A](var story: String) extends Novel[A] {
type T = ShortStory[A]
def reverse : T = new ShortStory[A](story reverse)
def myMethod: Unit = println("a short story method")
}
scala> val ss1 = new ShortStory[String]("the story so far")
ss1: ShortStory[String] = ShortStory@5debf305
scala> val ssRev = ss1 reverse
ssRev: ss1.T = ShortStory@5ae9581b
scala> ssRev story
res0: String = raf os yrots eht
scala> val ssRevRev = ss1 revrev
ssRevRev: ss1.T#T = ShortStory@2429de03
scala> ssRevRev story
res1: String = the story so far
scala> ssRevRev myMethod
a short story method
Run Code Online (Sandbox Code Playgroud)
它当然很小,但我怀疑这是否足以被用作一种框架.当然,返回的类型并不像Scala集合框架那样清晰,所以这可能有点过于简单.然而,对于给定的情况,它似乎完成了这项工作.如上所述,对于给定的情况,这不起作用,因此这里需要一些其他解决方案.
然而另一个编辑:类似的东西也可以使用具体的类来完成,尽管这也不足以成为类型安全:
class Novel[A](var story: String) {
type T <: Novel[A]
def reverse: T = new Novel[A](story reverse).asInstanceOf[T]
def revrev : T#T = reverse.reverse
}
class ShortStory[A](var s: String) extends Novel[A](s) {
type T = ShortStory[A]
override def reverse : T = new ShortStory(story reverse)
def myMethod: Unit = println("a short story method")
}
Run Code Online (Sandbox Code Playgroud)
代码将像特征示例一样工作.但它也遇到了与Rex在他的编辑中提到的相同的问题.ShortStory的覆盖不是进行此编译所必需的.但是,如果不执行此操作并在ShortStory实例上调用reverse方法,它将在运行时失败.
我还没有完全考虑清楚,但它进行了类型检查:
object invariant {
trait Novel[A] {
type Repr[X] <: Novel[X]
def reverse: Repr[A]
def revrev: Repr[A]#Repr[A]
= reverse.reverse
}
class ShortStory[A] extends Novel[A] {
type Repr[X] = ShortStory[X]
def reverse = this
}
val ss = new ShortStory[String]
val ss2: ShortStory[String] = ss.revrev
}
object covariant {
trait Novel[+A] {
type Repr[X] <: Novel[_ <: X]
def reverse: Repr[_ <: A]
def revrev: Repr[_ <: A]#Repr[_ <: A] = reverse.reverse
}
class ShortStory[+A] extends Novel[A] {
type Repr[X] = ShortStory[X]
def reverse = this
}
val ss = new ShortStory[String]
val ss2: ShortStory[String] = ss.revrev
}
Run Code Online (Sandbox Code Playgroud)
编辑
协变版本可以更好:
object covariant2 {
trait Novel[+A] {
type Repr[+X] <: Novel[X]
def reverse: Repr[A]
def revrev: Repr[A]#Repr[A] = reverse.reverse
}
class ShortStory[+A] extends Novel[A] {
type Repr[+X] = ShortStory[X]
def reverse = this
}
val ss = new ShortStory[String]
val ss2: ShortStory[String] = ss.revrev
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
602 次 |
| 最近记录: |