在Scala中的自类型特质中调用超类的方法
在Scala中的自类型特质中调用超类的方法
我正在尝试创建一个特质,当混入时,将替换方法的默认定义,改为调用原始方法,然后操作结果。
我想做的是这样的:
class Foo { def bar() : String = "Foos bar" } trait OtherStuff { self : Foo => def bar() : String = self.bar() + " with OtherStuff" } class Quux extends Foo with OtherStuff
如果这样工作的话,(new Quux).bar
现在将返回Foos bar with OtherStuff
。不幸的是,它并不起作用 - 我得到的是:
:6: 错误: 无法重写类Foo中的方法bar: ()String; 需要`override'修饰符的方法bar在特质OtherStuff中却没有重写任何东西 class Quux extends Foo with OtherStuff
但是,如果在定义OtherStuff
时使用override
,我得到的是:
:7: 错误: 方法bar没有重写任何东西 override def bar() : String = self.bar() + " with OtherStuff"
是否可能使用特质来重写自身类型的方法?如果不行,将OtherStuff
改为将extends Foo
的特质会对所有已存在的代码产生不良影响,比如
class WhatEver extends Foo with Xyz with Pqr with OtherStuff with Abc
我在使用scala 2.7.7,因为这是一个sbt构建规则,我们还没有将sbt项目升级到0.10.x版本。(我们依赖的插件还没有准备好)
问题的出现原因是在Scala中,当一个trait使用self类型注解时,它将会成为混入该trait的类的一部分,而不是一个子类型关系。在给定的示例中,OtherStuff trait被混入了Foo类中,因此OtherStuff中定义的bar方法实际上是Foo类的一部分。
问题的解决方法是在OtherStuff中对bar方法进行重载。通过重载,我们可以为bar方法提供不同的参数列表,并且使其与Foo类中的bar方法的签名不同,从而避免出现无限递归的情况。
下面是修改后的代码示例:
class Foo { def bar(): String = "Foos bar" } trait OtherStuff { self: Foo => def bar(s: String): String = self.bar() + s } class Quux extends Foo with OtherStuff println((new Quux).bar(" with other stuff")) // 输出:Foos bar with other stuff
在这个示例中,我们为bar方法添加了一个参数,并在OtherStuff中重载了该方法。在Quux类的实例上调用bar方法时,将会调用OtherStuff中重载的bar方法,而不会出现无限递归的情况。
通过这种方式,我们可以使用self类型注解来实现在trait中调用超类的方法,并通过重载来避免无限递归的问题。
在Scala中,我们可以使用自类型(self type)来确保一个trait只能被某些特定的类混入。自类型的一种常见用法是在trait中调用其超类的方法。然而,在某些情况下,当我们在自类型的trait中调用超类的方法时,可能会遇到问题。
一个例子是当我们希望在trait中调用其超类的方法时。我们可以使用"abstract override"修饰符来实现这一点。同时,我们不需要为trait指定自类型。以下是一个示例代码:
trait OtherStuff extends Foo { abstract override def bar() = super.bar() + " with OtherStuff" } class Quux extends Foo with OtherStuff
在上面的代码中,我们定义了一个名为OtherStuff的trait,它扩展了Foo trait,并重写了bar()方法。在bar()方法中,我们调用了super.bar()来调用Foo trait中的bar()方法,并在其结果后添加了一段字符串。然后,我们定义了一个名为Quux的类,它扩展了Foo trait,并混入了OtherStuff trait。这样,当我们调用Quux的bar()方法时,它会执行Foo trait中的bar()方法,并将结果与" with OtherStuff"字符串连接起来。
关于这个问题,有人提出了一个问题:如果OtherStuff在逻辑上不是Foo,是否还有其他解决方法而不需要扩展Foo?又或者,我是不是在滥用自类型?
对于第一个问题,如果OtherStuff在逻辑上不是Foo,那么我们确实需要扩展Foo并混入OtherStuff trait。这是因为我们需要在OtherStuff trait中调用Foo trait中的方法。如果OtherStuff不是Foo的子类,我们无法直接调用Foo trait中的方法。
对于第二个问题,滥用自类型是一个主观问题,取决于具体的使用场景和需求。自类型的主要目的是确保trait只能被特定的类混入。在某些情况下,可能需要在trait中调用超类的方法,这时使用自类型是合理的。然而,在其他情况下,如果没有必要使用自类型,滥用自类型可能会使代码更加复杂和难以理解。
总结起来,当我们需要在trait中调用其超类的方法时,可以使用"abstract override"修饰符,并混入该trait的类需要扩展超类。如果在逻辑上不是超类的子类,那么我们确实需要扩展超类。滥用自类型是一个主观问题,需要根据具体的使用场景和需求来判断。