Scala: Se intentó utilizar un método de extensión, pero no se pudo construir completamente (mismo nombre de extensión en múltiples clases)
En Scala, estoy tratando de definir un método de extensión en dos clases diferentes. Quiero que el método de extensión tenga el mismo nombre en ambas clases.
Ten en cuenta que las clases no están relacionadas por herencia.
Como ejemplo, digamos que tengo dos clases de caso A y B, cada una con una propiedad String, y quiero definir un método lower en ambas clases, que devuelva la versión en minúsculas de su propiedad:
import SomeObject.AExt.lower
import SomeObject.BExt.lower
object SomeObject {
case class A(foo: String)
case class B(bar: String)
object AExt {
extension (x: A) def lower = x.foo.toLowerCase
}
object BExt {
extension (x: B) def lower = x.bar.toLowerCase
}
def hello(): Unit = {
def a = A("foo")
def b = B("bar")
println(a.lower)
println(b.lower)
}
}
La compilación falla con este error:
Se intentó utilizar un método de extensión, pero no se pudo construir completamente:
SomeObject.BExt.lower(a) falló con
Encontrado: SomeObject.A
Requerido: SomeObject.B
Parece que el compilador está confundido y está intentando aplicar la extensión lower definida en la clase B a mi instancia de A.
davy.ai
Para definir un método de extensión con el mismo nombre en dos clases diferentes en Scala, puedes utilizar una técnica llamada “conversiones implícitas”. Así es cómo puedes modificar el código para lograrlo:
“`lang=scala
object SomeObject {
case class A(foo: String)
case class B(bar: String)
trait Lowerable {
def lower: String
}
implicit def aToLowerable(a: A): Lowerable = new Lowerable {
def lower = a.foo.toLowerCase
}
implicit def bToLowerable(b: B): Lowerable = new Lowerable {
def lower = b.bar.toLowerCase
}
def hello(): Unit = {
def a = A(“foo”)
}
}
“`
Esto es lo que hicimos:
Lowerable
que representa el aspecto “lowerable” de nuestras clases.A
yB
aLowerable
. Estas conversiones se utilizan por el compilador para convertir implícitamente instancias deA
yB
a instancias deLowerable
cuando sea necesario.lower
en el traitLowerable
, de modo que pueda ser llamado en instancias tanto deA
como deB
.hello
, ahora podemos llamar al métodolower
en las instanciasa
yb
, independientemente de su tipo.Con este enfoque, podemos definir cualquier número de métodos de extensión con el mismo nombre en clases diferentes, siempre y cuando podamos definir un trait o interfaz común que represente el aspecto común de esas clases.