kotlin:不同类型的通用

时间:2017-04-02 12:55:34

标签: generics kotlin

我需要像这样的线性函数:

class Linear(val a : Double, val b : Double) {
    fun eval(in : Double) {
        return a*in + b
    }
}

然后,我对矢量需要相同的东西。

class Vector3d(val a1 : Double, val a2 : Double, val a3 : Double) {
    // use operator overloading https://kotlinlang.org/docs/reference/operator-overloading.html to make +, -, /, *, etc. possible for vectors
}

class Linear(val a : Vector3d, val b : Vector3d) {
    fun eval(in : Vector3d) {
        return a*in + b
    }
}

如您所见,两个Linear类是相同的(参数类型除外)。现在,我不能使类通用,因为Double和Vector3d没有共同的超类。

如果我只想写一次Linear,我唯一的选择是我自己的Double-type,它与Vector3d有一个共同的接口。但是,这意味着我不能再在源代码中使用0,但我必须在任何地方使用MyDouble(0)。我可以重载Linear的构造函数来接受双打,并在内部创建MyDouble对象,但是,我需要为我的API中的每个方法执行此操作。

有更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

您可以通过定义具有两个实现/子类的接口/类来引入间接级别:一个用于原始双精度,一个用于Vector3d。但是,您可能会发现开销不合需要。 e.g:

interface Arithmetical<A : Arithmetical<A>> {
    operator fun plus(other: A): A
    operator fun minus(other: A): A
    operator fun times(other: A): A
    operator fun div(other: A): A
}

class Linear<A : Arithmetical<A>>(val a: A, val b: A) {
    fun eval(`in`: A): A {
        return a * `in` + b
    }
}

class ArithmeticalDouble(val value: Double) : Arithmetical<ArithmeticalDouble> {
    override fun plus(other: ArithmeticalDouble) = ArithmeticalDouble(value + other.value)
    override fun minus(other: ArithmeticalDouble) = ArithmeticalDouble(value - other.value)
    override fun times(other: ArithmeticalDouble) = ArithmeticalDouble(value * other.value)
    override fun div(other: ArithmeticalDouble) = ArithmeticalDouble(value / other.value)
}

class Vector3d(val a1: Double, val a2: Double, val a3: Double) : Arithmetical<Vector3d> {
    override fun plus(other: Vector3d): Vector3d = TODO()
    override fun minus(other: Vector3d): Vector3d = TODO()
    override fun times(other: Vector3d): Vector3d = TODO()
    override fun div(other: Vector3d): Vector3d = TODO()
}

这更容易听到处理原始双打的问题,因为现在你需要打包和解包它们,但它确实允许你使用泛型来定义Linear

答案 1 :(得分:0)

事实上,你在技术上可以使用泛型创建一个类,但是该类不知道如何将T与T相乘,因为它是Any的子类,{{1} }不支持这个操作符。通过smart-casts,您可以评估,给出了什么样的T:

Any

有关详细信息,请参阅Kotlin-docs上的generics

我不会考虑这个好习惯,因为该方法没有明确的(和类型保存)返回类型,并且非常不灵活,但至少它为您的参数提供了类型安全性。

另一种替代方法是使用class Linear<T>(val a: T, val b: T) { fun eval(c: T): Any { when { a is Double -> return a * c as Double + b as Double a is Double -> return a * c as Vector3d + b as Vector3d else -> return Unit } } (或Number)作为Double的超类,并将方法实现为length。这也不是一个很好的做法,但至少你可以使用Vector3d作为泛型。