2014-02-12 44 views
0

讓我們來看一個例子(這是一個天真的例子,但足以說明問題)。根據輸入參數返回不同類型

def produce(l: List[Int]) : Any = 
    l match { 
    case List(x) => x 
    case List(x, y) => (x, y) 
    } 

val client1 : Int = produce(List(1)).asInstanceOf[Int] 

缺點:客戶端需要投!

def produce2[A](l: List[Int])(f: List[Int] => A) = { 
    f(l) 
} 

val toOne = (l: List[Int]) => l.head 
val toTwo = (l: List[Int]) => (l.head, l.tail.head) 


val client2 : Int = produce2(List(1))(toOne) 

缺點:類型安全性,即我們可以通過一個單例列表調用toTwo。

有沒有更好的解決方案?

+0

標準斯卡拉'List'沒有抓住它的長度在其類型,所以你不能阻止'從toTwo'被稱爲列表元素太少的列表。使用「HList」(例如無形),可以做到這一點,因爲每個元素的類型(因此也就是內在的長度)是靜態已知的。如果我真的知道如何編寫特定的代碼,我會做出這個答案,但是我對Shapeless和'HList'的瞭解只是「理論上的」。無形:https://github.com/milessabin/shapeless –

回答

3

如果你只有兩個可能的返回值,你可以使用任一:

def produce(l : List[Any]) : Either[Any, (Any, Any)] = l match { 
    case List(x) => Left(x) 
    case List(x, y) => Right((x, y)) 
} 

如果你不希望創建一個Either,你可以將一個函數變換各種情況:

def produce[A](l : List[Int])(sf: Int => A)(pf: (Int, Int) => A): A = l match { 
    case List(x) => sf(x) 
    case List(x, y) => pf(x, y) 
} 
+0

好主意使用'無論',但客戶端仍然需要一些樣板來從'Left'或'Right'提取值,就像我的第一個解決方案。 –

+0

我喜歡這個想法來傳遞處理匹配結果的函數。 – Madoc

0

這項工作?

def produce(l: List[Int]) = { 
    l match { 
     case List(x) => (x, None) 
     case List(x,y) => (x,y) 
     case Nil => (None, None) 
    } 
    } 

,甚至更好,避免對名單比2組的元素不再匹配誤差:

def produce(l: List[Int]) = 
    l match { 
     case x :: Nil => (x, None) 
     case x :: xs => (x,xs.head) 
     case Nil => (None, None) 
    } 
+0

它會返回(任何,任何),遠離我想要的強打字。 –

相關問題