2014-02-12 47 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

它会返回(任何,任何),远离我想要的强打字。 –

相关问题