是否可以从 self 类型调用重写的方法? [英] Is it possible to call an overridden method from self type?
问题描述
考虑一下:
class Foo { def foo = "foo" }trait Bar { self: Foo =>覆盖 def foo = "bar"}
我惊喜地发现这是可能的,并且按预期工作:
带有 Bar foo 的新 Foo
返回bar".问题是 Bar.foo
是否有可能调用 Foo.foo
,就像在普通"继承情况下经常做的那样.override def foo = super.foo + "bar"
不起作用(说foo 不是 AnyRef 的成员),并且 override def foo = self.foo + "bar"
(它最终只是调用自己,并导致无限递归).我尝试了一些其他组合(如 self.Foo.foo
、Foo.this.foo
等),但没有任何运气.
这是不可能的吗?
没有.无法从 self 类型调用覆盖方法.
首先,特征 Bar
不是 Foo
类的继承者,所以不可能使用 super.foo
.
其次也不可能使用 self.foo
,因为 self
实际上是 Bar with Foo
类型.可以通过在typer
后打印程序来显示:
$ scalac -Xprint:typer test.scala[[typer 末尾的语法树]]//test.scala包<空>{类 Foo 扩展了 scala.AnyRef {def (): Foo = {Foo.super.();()};def foo: String = "foo"};抽象 trait Bar extends scala.AnyRef { self: Bar with Foo =>def/*Bar*/$init$(): 单位 = {()};覆盖 def foo: String = "bar"};class FooBar 使用 Bar { 扩展 Foodef (): FooBar = {FooBar.super.();()}};对象 TestApp 扩展了 scala.AnyRef {def (): TestApp.type = {TestApp.super.();()};def main(args: Array[String]): Unit = {val a: FooBar = new FooBar();scala.this.Predef.println(a.foo)}}}
因此,使用 self.foo
,您正在尝试访问特征 Bar
的方法 foo
.此类行为符合 Scala 规范 (PDF):
模板语句的序列可以用一个正式的前缀参数定义和箭头,例如x =>,或 x:T =>.如果正式给定参数,它可以用作引用 this 的别名整个模板主体.如果形参来对于类型 T,此定义会影响对象的自身类型 S底层类或对象如下:令 C 为类的类型或特征或定义模板的对象.如果给定了类型 T形式自参数,S 是 T 和 C 的最大下界.如果没有给出了类型 T,S 就是 C.在模板内部,this 的类型是假设为 S.
可以使用反射访问该方法,但我认为这不是您要找的.p>
Consider this:
class Foo { def foo = "foo" }
trait Bar { self: Foo =>
override def foo = "bar"
}
I was pleasantly surprised to find out that this is possible, and works as expected:
new Foo with Bar foo
returns "bar". The question is whether it is possible for Bar.foo
to invoke Foo.foo
, like one would often do in the "ordinary" inheritance case. override def foo = super.foo + "bar"
does not work (says "foo is not a member of AnyRef), and neither does override def foo = self.foo + "bar"
(it ends up just calling itself, and results in infinite recursion).
I tried a few other combinations (like self.Foo.foo
, Foo.this.foo
etc.), but without any luck.
Is this just impossible?
No. It is impossible to call overridden method from a self type.
Firstly the trait Bar
is not a successor of class Foo
so it is not possible using super.foo
.
And secondly it is also not possible using self.foo
since self
is actually of type Bar with Foo
. It can be shown by printing the program after typer
:
$ scalac -Xprint:typer test.scala
[[syntax trees at end of typer]] // test.scala
package <empty> {
class Foo extends scala.AnyRef {
def <init>(): Foo = {
Foo.super.<init>();
()
};
def foo: String = "foo"
};
abstract trait Bar extends scala.AnyRef { self: Bar with Foo =>
def /*Bar*/$init$(): Unit = {
()
};
override def foo: String = "bar"
};
class FooBar extends Foo with Bar {
def <init>(): FooBar = {
FooBar.super.<init>();
()
}
};
object TestApp extends scala.AnyRef {
def <init>(): TestApp.type = {
TestApp.super.<init>();
()
};
def main(args: Array[String]): Unit = {
val a: FooBar = new FooBar();
scala.this.Predef.println(a.foo)
}
}
}
So with self.foo
you are trying to access the method foo
of the trait Bar
. Such behavior matches the Scala Specification (PDF):
The sequence of template statements may be prefixed with a formal parameter definition and an arrow, e.g. x =>, or x: T =>. If a formal parameter is given, it can be used as an alias for the reference this throughout the body of the template. If the formal parameter comes with a type T, this definition affects the self type S of the underlying class or object as follows: Let C be the type of the class or trait or object defining the template. If a type T is given for the formal self parameter, S is the greatest lower bound of T and C. If no type T is given, S is just C. Inside the template, the type of this is assumed to be S.
It is possible to access the method using reflection but I think that it is not what you are looking for.
这篇关于是否可以从 self 类型调用重写的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!