es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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.

Tags:  , ,

Answer

  1. Avatar for 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”)

    def b = B("bar")
    
    println(a.lower)
    println(b.lower)
    

    }
    }
    “`

    Esto es lo que hicimos:

    • Definimos un trait Lowerable que representa el aspecto “lowerable” de nuestras clases.
    • Definimos dos conversiones implícitas de A y B a Lowerable. Estas conversiones se utilizan por el compilador para convertir implícitamente instancias de A y B a instancias de Lowerable cuando sea necesario.
    • Definimos el método lower en el trait Lowerable, de modo que pueda ser llamado en instancias tanto de A como de B.
    • En el método hello, ahora podemos llamar al método lower en las instancias a y b, 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.

Comments are closed.