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.

Forma concisa de implementar la misma función para un tipo de retorno de subclase.

Tengo una anulación del operador de multiplicación en mi clase base.

open class Tuple(
    open val x: Double,
    open val y: Double,
    open val z: Double,
    open val w: Double
) {
open operator fun times(scalar: Double) = Tuple(x * scalar, y * scalar, z * scalar, w)
}

Me gustaría que esta anulación del operador funcione exactamente de la misma manera para las subclases.

data class Point(
    override val x: Double,
    override val y: Double,
    override val z: Double
) : Tuple(x, y, z, 1.0) {

Intento 1:

override operator fun times(scalar: Double) = Point(x * scalar, y * scalar, z * scalar)

Intento 2:

private fun toPoint(other: Tuple) = Point(other.x, other.y, other.z)
operator fun times(scalar: Double) = toPoint(super.times(scalar))
}

Pero en lugar de eso, quiero que devuelva la subclase, lo cual requiere un subconjunto de parámetros de la clase base para ser instanciada.

¿Existe alguna forma de escribir solo una función y hacer que devuelva el tipo correspondiente según el tipo de clase de entrada?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Sí, esto se puede lograr utilizando una técnica llamada tipo de retorno covariante. Para hacer que la anulación del operador de multiplicación funcione de la misma manera para las subclases, simplemente podemos anular la función times() en la subclase y cambiar su tipo de retorno al tipo de subclase correspondiente.

    Aquí tienes un ejemplo de cómo se puede hacer:

    open class Tuple(
        open val x: Double,
        open val y: Double,
        open val z: Double,
        open val w: Double
    ) {
    
        open operator fun times(scalar: Double) = Tuple(x * scalar, y * scalar, z * scalar, w)
    }
    
    data class Point(
        override val x: Double,
        override val y: Double,
        override val z: Double
    ) : Tuple(x, y, z, 1.0) {
    
        override fun times(scalar: Double): Point = Point(x * scalar, y * scalar, z * scalar) 
    }
    

    Observa que hemos cambiado el tipo de retorno de la función times() a Point. Esto es posible porque Point es una subclase de Tuple, y así podemos utilizar el tipo de retorno covariante para devolver el tipo de subclase correspondiente.

    Ahora, si creamos una instancia de la clase Point y llamamos a la función times() en ella, devolverá un objeto de tipo Point en lugar de un objeto de tipo Tuple:

    val p = Point(1.0, 2.0, 3.0)
    val result = p * 2.0 // Devuelve un objeto de tipo Point
    

    De esta manera, podemos tener una sola función que funcione para todas las subclases y devuelva el tipo de subclase correspondiente.

Comments are closed.