我正在学习Scala和有一件事,我无法了解的语言:
前段时间我在Lisaac很舒服的编程,并在Lisaac我可以写一个类PERSON
带槽list:ARRAY[SELF]
,这相当于有list:ARRAY[PERSON]
因为SELF
是对象的类型其中该时隙的。
但是,通过使用SELF
,如果我写第二类STUDENT
是继承自PERSON
,那么STUDENT
将继承该插槽改变SELF
的STUDENT
,让STUDENT
将有一个列表STUDENT
,而不是PERSON
。
能在斯卡拉做什么? 我不能了解的事情。
谢谢!
我不知道这是否会真正对你有用,但我能想到的最接近的是this.type
。 例如:
scala> class A { val l: List[this.type] = Nil }
defined class A
scala> new A().l
res3: List[A] = List()
scala> class B extends A
defined class B
scala> new B().l
res4: List[B] = List()
有这个成语,它是在集合框架中广泛使用(在所有*像类一样,如TraversableLike)。 您需要添加自类型作为类型参数(如可能出现在C ++与CRTP超类的):
trait Person[+Self] {
this: Self => //Declare that any concrete subclass must implement Self; therefore, this can be used with type Self.
//val list: Array[Self] //Not sure that this will work so easily, for the same reason new T[] does not work in Java.
val list = Seq[Self]() //No problem here; Array is really special.
}
定义这个类之后,我们可以尝试在解释定义的子类:
scala> class Student extends Person[Student]
defined class Student
scala> (new Student).list
res0: Seq[Student] = List() //Note the result type
scala> class Student2 extends Person[Student] //Note the mistake
<console>:9: error: illegal inheritance;
self-type Student2 does not conform to Person[Student]'s selftype Person[Student] with Student
class Student2 extends Person[Student]
这不阻止甲错误是具有这种定义,其中自未重定义:
scala> class SpecStudent extends Student
defined class SpecStudent
得益于+
面前Self
,这使得它一个协变类型参数(我不解释那是什么),但是这至少是可能的:
scala> class SpecStudentCorrect extends Student with Person[SpecStudentCorrect]
scala> (new SpecStudentCorrect).list
(new SpecStudentCorrect).list
res1: Seq[SpecStudentCorrect] = List()
在this
关键字在Scala是或多或少等价物。
在开发可扩展的软件,有时得心应手声明价值的类型this
明确:
Scala中显式类型自我引用
http://www.scala-lang.org/node/124
单身类型和ETSR的不解决这个问题。 我自己一直在寻找的只是在斯卡拉相同的功能,但显然它缺乏所谓的自我型的注释。
有些情况下,这种自我类型注释可能是非常有用的。 考虑一个例子(改编自循环型参数质疑例子 ):
// we want a container that can store elements
trait Container[E <: Element[E]] {
def elements: Seq[E]
def add(elem: E): Unit
}
// we want elements be aware of their enclosing container
trait Element[E <: Element[E]] {
def container: Container[E]
}
比方说,你把那到库。 一个图书馆消费者应做到以下几点:
object PersonContainer extends Container[Person] {
// actual implementation is not important
def elements = Nil
def add(p: Person) = {}
}
class Person extends Element[Person] { // {1}
def container = PersonContainer
}
这是好吧,一切都工作得如预期。 这涉及的唯一的事情就是一个图书馆消费者应该使用自我约束类型参数(代码中的#1)。 但是,这还不是全部。 现在,假设你有某种考虑一个ActiveRecord的模式,你要添加的方法save
到Element
,这只是委托给它的容器的add
方法。 出人意料的是,它不是那么容易:
trait Element[E <: Element[E]] {
def container: Container[E]
def save() = container.add(this) // won't compile
}
found : Element[E]
required: E
直观地说,我们有几种选择在这里:
- 使
add
方法接受Element[E]
代替E
; - 投
this
对Element[E]
这些选项无是令人满意的,只是因为这样的事实E
是不一样的Element[E]
实施方式并不强迫使用自粘结型参数)。 我看到解决这个问题的唯一方法是在斯卡拉,自我型概念(让我们假设我们有它在我们最喜欢的语言):
trait Container[E <: Element] {
def elements: Seq[E]
def add(elem: E): Unit
}
trait Element { // the type parameter would be redundant ...
def save() = container.add(this) // ... and this would be possible, too, ...
def container: Container[this] // ... if only we could do this
}
如果编译器可以把this
当它被用来在方括号内,作为实际实现的类型(即相同类型的结果(或者另一个关键字), obj.getClass
),那么问题就会消失。
PS可能有人考虑将这种东西放进了Scala的心愿? 不幸的是,我不知道,这是多么难以实现这样的逻辑,因为有可能是与臭名昭著的JVM的擦除的问题。
PPS或者,也许有一些其他的Scala路,我不知道的?