为什么这个“别名”在Scala中起作用?
为什么这个“别名”在Scala中起作用?
在Coursera课程“响应式编程原理”中,Odersky介绍了以下代码片段:
trait Generator[+T] { self => // “this”的别名。 def generate: T def map[S](f: T => S): Generator[S] = new Generator[S] { def generate = f(self.generate) } def flatMap[S](f: T => Generator[S]): Generator[S] = new Generator[S] { def generate = f(self.generate).generate } }
然而,我对self =>
这个东西不太熟悉。为什么它可以工作,为什么我不能只是用val self = this
?
在Scala中,为什么这个“别名”在代码中起作用?
在Scala中,有一个问题需要解决,即在map和flatMap方法中,需要从新创建的内部Generator中引用外部的Generator。如果在代码中使用this代替self,就无法识别外部Generator,而是识别内部的Generator。因为this始终指的是离使用它的位置最近的类实例。
为了解决这个问题,可以添加一个self方法来引用外部的Generator。但是在内部作用域中,新创建的Generator会有自己的self方法,从而再次调用了错误的self方法。
相比之下,别名并不是一个方法,在代码示例中并不存在“两次”,因此当你写下new Generator时,并不存在遮蔽的情况。这只是一个更简洁的方式,用于捕获外部实例并在内部引用它。
解决方法是在map方法中添加一个内部变量outer来捕获外部实例,然后在内部引用outer实例来调用generate方法。下面是代码示例:
def map[S](f: T => S): Generator[S] = { val outer = this // capture outer instance, since `this` will change meaning new Generator[S] { def generate = f(outer.generate) // refer to the outer instance } }
通过这种方式,我们可以正确引用外部的Generator,解决了问题。