用元组定义一个函数

时间:2011-06-28 23:57:31

标签: scala

如何定义一个接受所有元组(1到22)作为参数的函数,我有以下内容:

def foo (v=Tuple) =...

foo((1,2))
foo((1,2,3))

修改

回答评论:我实际上是在尝试创建一个Tensor类,它是一组值和一组索引。指数可以是协变的和/或逆变的(cf Wikipedia1Wikipedia2)。我希望有一个特殊的语法,如Tensor((1,2),(3,4),values),它将创建一个带有values的张量,两个具有长度(2,3)的协变索引和两个长度为(3,4)的逆变索引。因此,使用这种语法,我也可以编写Tensor((1,2,3),3,values)(使用隐式Int => Tuple1)。

我同意Tuple不适合这种情况,最好使用List。然而,语法不是那么好......

6 个答案:

答案 0 :(得分:4)

这真的isn't what tuples are for(参见评论和答案here)。元组用于执行诸如从方法返回多个值的操作,在Java中您必须创建轻量级类。如果您有任意数量的元素,则应使用集合。

答案 1 :(得分:4)

为用户提供方便的API的另一种方法(implicit conversion除外)是使用带有varargs的多个参数列表:

def tensor(cov: Int*)(contrav: Int*)(values: Int*) = // ...

您的示例将被编写

tensor(1,2)(3,4)(values)
tensor(1,2,3)(3)(values)

答案 2 :(得分:3)

没有专门针对元组的特性,但您可以使用类型类方法as demonstrated in this answer

如果您的目标确实是拥有List但允许调用者传入元组(为方便起见),您可以修改该解决方案,以便类型类生成List而不是Product。

简而言之,我们的想法是,您可以从调用者可以传递给您实际要使用的类型的类型中提供隐式转换:

def foo(x: IndexList) = x.indices

sealed case class IndexList(indices: List[Int])

object IndexList {
   implicit def val2indices(i: Int) = IndexList(List(i))
   implicit def tuple2toIndices(t: (Int, Int)): IndexList = 
      product2indices(t)
   // etc
   implicit def list2indices(l: List[Int]) = IndexList(l)

   private def product2indices(p: Product) = 
      IndexList(p.productIterator.toList.asInstanceOf[List[Int]])
}

然后,您可以使用您提供转换的任何类型调用您的方法:

foo(1)
foo((2,3))
foo(List(1,2,3))

答案 3 :(得分:1)

所有案例类,包括元组,都扩展scala.Product,但不幸的是,没有专门针对元组的标记特征,所以有人可以将普通的案例类隐藏到你的方法中。当然,没有办法以统一的方式处理所有的arities并且仍然是类型安全的,但你可以使用productElement(n: Int)来提取第n个值,或productIterator来迭代所有的值。

但是......这是异端邪说,你有没有考虑过载? :)

答案 4 :(得分:1)

您可能想要使用的是 HList ,而不是元组。 HList(异类列表)基本上是一个任意长度的类型元组。

scala中有一些HLists示例(它们不属于标准库)

答案 5 :(得分:0)

检查一下。它实际上比我预期的更好;)

scala> def f[T <: Product](x: T) = x
f: [T <: Product](x: T)T

scala> f(1)
<console>:9: error: inferred type arguments [Int] do not conform to method f's type parameter bounds [T <: Product]

scala> f(1, "2") // you don't even need the extra parenthesis
res0: (Int, java.lang.String) = (2,3)

scala> f(1, "2", BigInt("3"))
res1: (Int, java.lang.String, scala.math.BigInt) = (1,2,3)