2017-08-24 59 views
0

現在我有一個RealVector類和ComplexVector類。他們的邏輯幾乎完全相同,所以我想將它們合併成一個Vector類。 RealVector需要List[Double]ComplexVector需要List[ComplexNumber]其中ComplexNumber是我創建的案例類。如何重載我的案例類構造函數以允許兩種不同的類型?

我該怎麼做才能讓我的case class Vector接受兩種List類型之一?請注意,雖然大多數方法的代碼是相同的,但其中一些方法可能會返回DoubleComplexNumber,具體取決於List類型。在這種情況下使用case類還是正確的,還是應該使用普通類?

編輯:我當前的代碼

trait VectorElement[A] 
implicit object RealVectorElement extends VectorElement[Double] 
implicit object ComplexVectorElement extends VectorElement[ComplexNumber] 

case class MyVector[A: VectorElement](components: List[A]) { 
    def +(that:MyVector[A]):MyVector[A] = { 
     if (this.dimension != that.dimension) throw new Exception("Cannot add MyVectors of different dimensions."); 
     new MyVector((this.components zip that.components).map(c => c._1 + c._2)); 
    } 

    def -(that:MyVector[A]):MyVector[A] = { 
     if (this.dimension != that.dimension) throw new Exception("Cannot subtract MyVectors of different dimensions."); 
     new MyVector((this.components zip that.components).map(c => c._1 - c._2)); // ERROR HERE: error: value - is not a member of type parameter A 
    } 
    ... 
} 
+0

太寬泛得到建設性的答案,而不是超載,可能是各種更好的解決方案,作爲'trait',genericity,typeclass,... https://stackoverflow.com/help/how-to-ask – cchantep

+0

輔助構造函數需要調用主構造函數,這可能會使方法難以確定使用哪個構造函數。 – jwvh

回答

1

你可以嘗試使用一些更高級的Scala的類型系統的特點:

object Types { 
    trait inv[-A] {} 
    type Or[A, B] = { 
    type check[X] = (inv[A] with inv[B]) <:< inv[X] 
    } 
} 

case class Vector[U : (Double Or Int)#check](list: List[U]) { 
    def first(): U = list.head 
} 

我用DoubleInt在這裏,但任何類型都可以用過的。用法很簡單:

println(Vector(List(1.0, 2.0, 3.0)).first()) // prints a Double 
println(Vector(List(1, 2, 3)).first()) // prints an Int 
//Vector(List("String")).first() // won't compile 
2

最familar的方式是創建一個共同的超類型你的兩個向量類

abstract class Vector[A](elements: List[A]){ 
    //common code 
} 
case class RealVector(elements: List[Double]) extends Vector[Double](elements) 
case class ComplexVector(elements: List[ComplexNumber]) extends Vector[ComplexNumber](elements) 

的。如果你只是想要一個單一類型可以使用泛型與案例類如case class Vector[A](values: List[A])工程。

現在,這將允許任何類型的列表,所以讓我們縮小範圍。如果我們正在處理自定義類型,我們可以使用特徵中的常見超類型,但內置Double,我們不能修改它。

我們可以做的是使用一個typeclass,這是一個靈活的形式polymarhism可能在scala中。我們可以定義我們的類型類具有特徵。

trait VectorElement[A] 

如果我們只是想用它來標記我們想要的,我們完成的類型,但我們也可以把我們需要進到這裏,以及常用功能。

如果我們修改我們的例子類定義

case class Vector[A: VectorElement](values: List[A]) 

我們限制我們的泛型類型,只有那些類型的可用VectorElement實例。上面的代碼是爲case class Vector[A](values: List[A])(implicit ev: VectorElement[A])

,我們現在可以爲我們所需要

implicit object RealVectorElement extends VectorElement[Double] 
implicit object ComplexVectorElement extends VectorElement[ComplexNumber] 
現在

只要這兩個隱式對象的範圍,我們可以使用這些類型我們Vector類類型創建實例語法糖,但沒有其他人。


一些不相關的建議:

Vector已經從它總是自動導入標準庫類,這有可能導致問題

List潛在的可能不是最好的集合類型這是因爲它需要遍歷集合來訪問它的元素。可能你想選擇更通用的東西,並且你可能想要良好的索引訪問。如果您使用IndexedSeq而不是List作爲集合類型,則可以確保您正在使用具有基於索引的隨機訪問(如ArrayVector(標準庫中的一個))的集合。

+0

這樣做後,我得到了錯誤'錯誤:值 - 不是類型參數A'的成員,但我'''重寫/定義爲'ComplexNumber'和一個隱式轉換的'雙'。任何想法爲什麼?感謝IndexedSeq上的領導。我想要一些不可變的東西,這就是爲什麼我沒有使用Array。 – Mike

+0

@Mike我需要看你的代碼。你想在哪裏調用價值?我懷疑這是因爲你試圖用'A'類型來調用它。請記住,您將無法調用'A'類型的ComplexNumber方法,因爲兩者不相關。你應該在類型類中定義你需要的任何方法。 – puhlen

+0

我添加了我的代碼作爲編輯。我認爲你對我的問題是正確的。我不認爲我想要一個解決方案,儘管我不能使用我的'ComplexNumber'方法,因爲我不想在我的類型類型和'ComplexNumber'中定義我的方法。 – Mike

相關問題