2015-05-11 42 views
2

如果我要拍,增加了像兩個不同類型的值的add方法:斯卡拉:函數返回一個未知類型

add[T,S](op1: T, op2: S): ? = ... 

最顯着的例子,我能想到的是基本的數字類型。如果我添加一個字節和一個Int,那麼它會返回一個Int。如果添加了兩個字節,它可能會返回一個Int,具體取決於字節的-127到128限制是否被破壞。

此外,如果我想創建具有相同特徵的類,我希望它也這樣做。

一個可能的解決方案是讓類擴展相同的特徵或類。但是對於Scala基元類型的例子,這不適用,因爲Int,Double,Float,Byte除了Any之外不共享一個共同的祖先。

我也看過數字[T]的特點,但似乎沒有幫助添加不同的基元類型時。

感謝 凱

回答

5

這是一個某種聯合類型類的一個最好的例子。

開始通過定義就像Numeric[T]的事情,但對於addability:

trait Addable[T, S] { 
    type Result 
    def add(x: T, y: S): Result 
} 

現在,定義add功能:

def add[T,S](op1: T, op2: S)(implicit op: Addable[T, S]): op.Result = 
    op.add(op1, op2) 

所有你需要做的離開,是創造隱含實例對於Addable

// Put them in the companion object, so the implicits are available 
// without explicit import 
object Addable { 
    // Make any numeric addable 
    implicit def numericAddable[T : Numeric]: Addable[T, T] = { 
    new Addable[T, T] { 
     type Result = T 
     def add(x: T, y: T): T = { 
     val op = implicitly[Numeric[T]] 
     op.plus(x, y) 
     } 
    } 
    } 
} 

Bu T優現在也可以定義自己的類別和定義(不對稱)除了能力:

case class A(x: Int) 
case class B(x: Int) 
case class C(x: Int) 

implicit object AddABC extends Addable[A,B] { 
    type Result = C 
    def add(x: A, y: B): C = C(x.x + y.x) 
} 

這將允許你寫:

add(A(1), B(2)) 

然而,他們都會讓你在編譯時失敗:

add(A(1), A(2)) 
add(B(1), A(2)) 
add(B(1), B(2)) 

不幸的是,這並不弱符合數字工種:

add(1, 1) // compiles 
add(1.0, 1.0) // compiles 
add(1, 1.0) // fails to compile 

another post判斷,除了手動定義案例(當然有一些輔助方法),實際上並沒有其他方法可以實現這一點。

+0

所以我剛剛花了今天研究你的解決方案和你鏈接到的一個。學習一些新東西,我第一次瞭解到無論怎樣,字節+字節都返回一個int!但是,有什麼理由不依賴於字節的值?如果通過將字節保持在其數字範圍內,可以節省空間,這似乎有點低效。 如果我想在我的代碼中進行以下操作,我一直在尋找Scalas「Either」類型。在這種情況下,我將返回一個Either,然後在添加包裝類時返回模式匹配。只是想知道是否有什麼特別的原因。 – Vangogh500

+0

在Scala中,字節+字節返回一個整數,主要是因爲這是JVM(和Java)的作用。我不知道爲什麼Java是這樣設計的。 – gzm0