假设我们有…
class Outer(val name : String):
class Inner:
def thump = s"${name}'s heartbeat"
我们想写一个函数,它接受任何可能未知的外部变量的内部变量。轻松peasy与投影类型!
def stethoscope( inner : Outer#Inner ) = inner.thump
这可以正常工作,而且显然依赖于inner
保留对其封闭示例的引用。
但是有没有可能写一个函数,
def enclosingInstance( inner Outer#Inner ) : Outer = ???
假设类的定义超出了我们的控制范围。
(So例如,我们不能将方法添加到内部引用到Outer
的自引用。
1条答案
按热度按时间wgeznvg71#
当我们编译时:
内部类的定义可能看起来像这样:
正如我们看到的,对
$outer: Outer
的引用是private
,所以我们不能以“法律的”方式访问它。Outer$Inner$$$outer(): Outer
是public
...但是如果我们试图调用它,编译器不知道这样的符号,这是有意义的,因为它是在稍后发出字节码时生成的,所以例如。typechecker阶段可能不知道它(或者假装不知道)。Scala的内部可以使用它来访问它,当一些代码必须合法访问它时(例如,在某些上下文中,
Outer.this
是法律的),但是用户可能没有法律的方式来调用它。我们可以通过运行时反射来“破解”这个限制:
See scastie.
我不建议依赖这样的技巧-因为名称是自动生成的,你必须例如。列出所有声明的字段,并检查其中哪些是:
private
final
Class[Outer]
不要依赖这个生成的名称在将来不会改变(可能不会,但我不会拿我的薪水打赌)。我也会检查这是否真的是我可以获得
Outer
示例的唯一方法(也许将它们与[O <: Outer](o: Outer, i: o.Inner)
沿着传递是可能的?).但如果你真的必须这么做,你就做你该做的。
也许(我没有检查)-在Scala 3的编译时反射中可见的声明定义列表将能够看到
Outer$Inner$$$outer()
,所以也许enclosingInstance
也可以作为宏实现(类似于你不能手动调用方法来定义某些方法的默认值,但在宏中你可以访问这些方法-例如。def methodname(a: Int = 1)
生成methodname$default$1
,你不能在普通代码中调用它,但你可以在宏中调用它)。