Inheritance 是否有一个“问题”;“自我”;是否在表示当前类型的scala中键入?

Inheritance 是否有一个“问题”;“自我”;是否在表示当前类型的scala中键入?,inheritance,scala,Inheritance,Scala,我正在学习Scala,但有一件事我找不到: 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, ...

我正在学习Scala,但有一件事我找不到:

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
}
不久前,我在Lisaac中编程非常自如,在Lisaac中我可以编写一个类
PERSON
,其中包含一个插槽
list:ARRAY[SELF]
,这相当于拥有
list:ARRAY[PERSON]
,因为
SELF
是该插槽所在对象的类型

但是通过使用
SELF
,如果我写了一个从
PERSON
继承的第二个类
STUDENT
,那么
STUDENT
将继承
STUDENT
的槽位更改
SELF
,因此
STUDENT
将有一个
STUDENT
的列表,而不是
PERSON

这可以在Scala中实现吗?关于那件事我什么也找不到


谢谢

Scala中的
这个
关键字或多或少是等效的

在开发可扩展软件时,有时可以方便地明确声明值的类型
this

在Scala中显式键入自引用

我不确定这是否真的对您有用,但我能想到的最贴切的事情是
这个。键入
。例如:

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()

单例类型和ETSR不能解决这个问题。我自己也在Scala中寻找同样的特性,但显然它缺少所谓的自类型注释

在某些情况下,此类自类型注释可能非常有用。考虑一个例子(改编自):

一切正常,一切正常。唯一值得关注的是,库使用者应该使用自绑定类型参数(代码中的#1)。但这还不是全部。现在假设您考虑了某种类型的ActiveRecord模式,并且希望将方法
save
添加到
元素
,该方法只委托给它的容器的
add
方法。令人惊讶的是,这并不那么容易:

trait Element[E <: Element[E]] {
  def container: Container[E]
  def save() = container.add(this)   // won't compile
}

found   : Element[E]
required: E
如果编译器可以在方括号内使用
this
(或者另一个关键字)作为实际实现的类型(即与
obj.getClass
的结果相同的类型),那么问题就会消失

有人会考虑把这些东西列入斯卡拉的愿望清单吗?不幸的是,我不知道实现这样的逻辑有多困难,因为臭名昭著的JVM擦除可能存在问题


p.p.S.或者可能还有另一种我不知道的Scala方式?

这有一个习惯用法,它在集合框架中被广泛使用(在所有类似*的类中,例如TraversableLike)。 您需要将自类型添加为类型参数(如C++中可能的)与超类:

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]
由于
Self
前面的
+
使其成为一个协变类型参数(我不解释它是什么),但这至少是可能的:

scala> class SpecStudentCorrect extends Student with Person[SpecStudentCorrect]

scala> (new SpecStudentCorrect).list
(new SpecStudentCorrect).list
res1: Seq[SpecStudentCorrect] = List()

我不认为“这个.类型”是这里所需要的。“this.type”是单例类型;它只是“this”实例的类型。尽管您可以尝试,但“List[this.type]”可以包含的有效元素是“this”。是的,您是对的。我试图准确地记住它是如何工作的。在trait元素中需要一个self-type注释:
trait元素[E…}
一旦你有了它,你就可以省去类型绑定。
this
关键字并不表示类型。>Scala中的this关键字或多或少是等价的。你指的是什么?如果它不等价于Lisaac的SELF(这是一种类型),那么你的意思是什么?OP要求一种表示类型的方法,因为他想写一些类似“Array[Self]”的东西。有一种常用的模式可以实现这一点,即使它有局限性(参见我的答案)。当然,我提供的链接澄清了问题。我看了一下;再看一遍,我意识到它显示了另一种解决方案,
Self
被声明为一个抽象成员,而不是一个参数。你确定这个超过两年的问题没有被接受的答案充分涵盖吗?如果你阅读了对answ的评论呃,你会同意我的。而且,你为什么认为我没有检查,甚至没有阅读接受的答案?现在,你提供的链接确实提供了一个比接受的答案更好的答案,但我确实发现你的答案的文本令人困惑。然而,我给出的解决方案是最常用的,也是因为它比o该链接中描述的ne:当
type
是同一类的抽象类型成员时,不能添加像
this:type=>
这样的自类型注释,但只有当它在外部类中时才可以。例如,trait Person{this:self=>type self}或
trait FooBase{type Bar};trait FooDer扩展FooBase{this:Bar=>}
可以工作,因为找不到
Bar
。这在嵌套多个需要这些自身类型的类型时特别有用。
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
scala> class SpecStudentCorrect extends Student with Person[SpecStudentCorrect]

scala> (new SpecStudentCorrect).list
(new SpecStudentCorrect).list
res1: Seq[SpecStudentCorrect] = List()