2017-04-02 27 views
1

我需要線性函數是這樣的:科特林:通用於不同類型的

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 
    } 
} 

如您所見,兩個線性類是相同的(參數類型除外)。現在,我不能讓類是泛型的,因爲Double和Vector3d沒有共同的超類。

如果我只想寫一次Linear,我唯一的選擇是我自己的Double-type,它與Vector3d有一個共同的接口。但是,這意味着我無法再在源代碼中使用0,但我必須在任何地方都使用MyDouble(0)。我可以重載Linear的構造函數來接受Doubles,並在內部創建MyDouble對象,但是,我需要爲我的API中的每個方法執行此操作。

有沒有更好的解決方案?

+0

你不顯示'Vector3d'如何支持'*'和'+'操作。你一定需要一個共同的父類/接口,否則你就會陷入不受約束的泛型。 – m0skit0

回答

0

實際上,您在技術上可以創建一個使用泛型的類,但是類不會知道如何將T與T相乘,因爲它是Any的子類,並且Any不支持該操作符。通過smart-casts你可以評估,給出了什麼樣的T:

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 
     } 
} 

有關更多信息,請參閱第科特林-docs的generics

我不會考慮這種好的做法,因爲該方法沒有明確的(和類型保存)返回類型,並且非常不靈活,但至少它爲您的參數提供了類型安全性。

另一種替代方法是使用Number(或Double)作爲Vector3d的超類,並將這些方法實現爲長度。這也不會是一個很好的做法,但至少你可以使用<Number>作爲泛型。

1

您可以通過定義具有兩個實現/子類的接口/類來引入一個間接級別:一個用於原始雙精度,另一個用於您的Vector3d。但是,您可能會發現不希望的開銷。例如: -

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更多偷聽。