Kotlin, generic operation on Number

2019-04-10 09:12发布

问题:

I have the following

abstract interface Vec2t<T : Number> {    
    var x: T
    var y: T
}

data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>

and I have an interface where I define several operations, e.g:

interface fun_vector2_common {

    fun abs(res: Vec2, a: Vec2): Vec2 {
        res.x = glm.abs(a.x)
        res.y = glm.abs(a.y)
        return res
    }
}

Is it possible to implement, let's say abs, by using generics?

interface fun_vector2_common<T : Number> {

    fun abs(res: Vec2t<T>, a: Vec2t<T>): Vec2t<T> {
        res.x = glm.abs(a.x)  // error
        res.y = glm.abs(a.y)  // error
        return res
    }
}

And then the corresponding glm.abs() based on the type will be called?

The above code fails because it expects, obviously, a glm.abs(n: Number)

回答1:

Unfortunately there's no clean way to have generic abs function. You can work it around with the following abs definition:

object glm {
    fun <T : Number> abs(x: T): T {
        val absoluteValue: Number = when (x) {
            is Double -> Math.abs(x)
            is Int -> Math.abs(x)
            is Float -> Math.abs(x)
            is BigDecimal -> x.abs()
            is BigInteger -> x.abs()
            else -> throw IllegalArgumentException("unsupported type ${x.javaClass}")
        }
        @Suppress("UNCHECKED_CAST")
        return absoluteValue as T
    }
}

Which would make it possible to use in your context:

fun abs(res: Vec2, a: Vec2): Vec2 {
    res.x = glm.abs(a.x)
    ...
}