scala - Cómo llamar al método súper al anular un método a través de un rasgo
polymorphism mixins (3)
Aquí está la respuesta que estaba buscando. Gracias a Shadowlands por indicarme la dirección correcta con la función de abstract override
de Scala.
trait Abstract extends Result {
abstract override def userRepr = "abstract " + super.userRepr
}
abstract class Result {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
val a = new ValDefResult("asd") with Abstract
a.userRepr
El código en vivo está disponible aquí: http://www.scalakata.com/52536cc2e4b0b1a1c4daa4a4
Perdón por el código de ejemplo confuso, estoy escribiendo una biblioteca que se ocupa de Scala AST y no estaba lo suficientemente inspirada para cambiar los nombres.
Parece que es posible cambiar la implementación de un método en una clase con un rasgo como el siguiente:
trait Abstract { self: Result =>
override def userRepr = "abstract"
}
abstract class Result {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
val a = new ValDefResult("asd") with Abstract
a.userRepr
El código en vivo está disponible aquí: http://www.scalakata.com/52534e2fe4b0b1a1c4daa436
Pero ahora me gustaría llamar a la implementación anterior o super de la función de la siguiente manera:
trait Abstract { self: Result =>
override def userRepr = "abstract" + self.userRepr
}
o
trait Abstract { self: Result =>
override def userRepr = "abstract" + super.userRepr
}
Sin embargo, ninguna de estas alternativas compila. ¿Alguna idea de cómo se podría lograr esto?
No sé si está en condiciones de realizar los siguientes cambios, pero el efecto que desea puede lograrse mediante la introducción de un rasgo adicional (lo llamaré Repr
) y el uso del abstract override
en el rasgo del Abstract
:
trait Repr {
def userRepr: String
}
abstract class Result extends Repr {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
trait Abstract extends Repr { self: Result =>
abstract override def userRepr = "abstract-" + super.userRepr // ''super.'' works now
}
Tu ejemplo de uso ahora da:
scala> val a = new ValDefResult("asd") with Abstract
a: ValDefResult with Abstract = ValDefResult(asd)
scala> a.userRepr
res3: String = abstract-asd
abstract override
es el mecanismo, también conocido como rasgos apilables. Vale la pena agregar que la linealización cuenta, porque eso es lo que determina lo que significa super
.
Esta pregunta es una gran adición a las preguntas y respuestas canónicas sobre auto-tipo vs extensión .
Donde la herencia es ambigua con los auto-tipos:
scala> trait Bar { def f: String = "bar" }
defined trait Bar
scala> trait Foo { _: Bar => override def f = "foo" }
defined trait Foo
scala> new Foo with Bar { }
<console>:44: error: <$anon: Foo with Bar> inherits conflicting members:
method f in trait Foo of type => String and
method f in trait Bar of type => String
(Note: this can be resolved by declaring an override in <$anon: Foo with Bar>.)
new Foo with Bar { }
^
Entonces, obviamente, puedes elegir:
scala> new Foo with Bar { override def f = super.f }
res5: Foo with Bar = $anon$1@57a68215
scala> .f
res6: String = bar
scala> new Foo with Bar { override def f = super[Foo].f }
res7: Foo with Bar = $anon$1@17c40621
scala> .f
res8: String = foo
o
scala> new Bar with Foo {}
res9: Bar with Foo = $anon$1@374d9299
scala> .f
res10: String = foo