Python对单个元素元组有(1,)
。在Scala中,(1,2)
适用于Tuple2(1,2)
,但我们必须使用Tuple1(1)
来获取单个元素元组。这可能看起来像一个小问题,但设计期望产品的API对于传递单个元素的用户来说很难处理,因为他们必须编写Tuple1(1)。
也许这是一个小问题,但Scala的一个主要卖点是打字更少,输入更少。但在这种情况下,似乎更多打字更多打字。
请告诉我: 1)我错过了这个,它以另一种形式存在,或者 2)它将被添加到该语言的未来版本中(并且他们将接受补丁)。
答案 0 :(得分:4)
您可以定义隐式转换:
implicit def value2tuple[T](x: T): Tuple1[T] = Tuple1(x)
隐式转换仅在参数的静态类型不符合方法参数的类型时才适用。假设您的方法采用Product
参数
def m(v: Product) = // ...
转化将应用于非产品价值,但不将适用于Tuple2
。警告:所有案例类都会扩展Product
特征,因此转换将不适用于它们。相反,product元素将是case类的构造函数参数。
Product
是TupleX
类的最小上限,但如果要将隐式Tuple1转换应用于所有非元组,则可以使用类型类:
// given a Tupleable[T], you can call apply to convert T to a Product
sealed abstract class Tupleable[T] extends (T => Product)
sealed class ValueTupler[T] extends Tupleable[T] {
def apply(x: T) = Tuple1(x)
}
sealed class TupleTupler[T <: Product] extends Tupleable[T] {
def apply(x: T) = x
}
// implicit conversions
trait LowPriorityTuple {
// this provides a Tupleable[T] for any type T, but is the
// lowest priority conversion
implicit def anyIsTupleable[T]: Tupleable[T] = new ValueTupler
}
object Tupleable extends LowPriorityTuple {
implicit def tuple2isTuple[T1, T2]: Tupleable[Tuple2[T1,T2]] = new TupleTupler
implicit def tuple3isTuple[T1, T2, T3]: Tupleable[Tuple3[T1,T2,T3]] = new TupleTupler
// ... etc ...
}
您可以在API中使用此类型类,如下所示:
def m[T: Tupleable](v: T) = {
val p = implicitly[Tupleable[T]](v)
// ... do something with p
}
如果您的方法退回产品,则可以看到如何应用转化:
scala> def m[T: Tupleable](v: T) = implicitly[Tupleable[T]](v)
m: [T](v: T)(implicit evidence$1: Tupleable[T])Product
scala> m("asdf") // as Tuple1
res12: Product = (asdf,)
scala> m(Person("a", "n")) // also as Tuple1, *not* as (String, String)
res13: Product = (Person(a,n),)
scala> m((1,2)) // as Tuple2
res14: Product = (1,2)
答案 1 :(得分:3)
当然,您可以向API添加隐式转换:
implicit def value2tuple[A](x: A) = Tuple1(x)
我觉得奇怪的是Tuple1.toString
包含尾随的逗号:
scala> Tuple1(1)
res0: (Int,) = (1,)
答案 2 :(得分:2)
Python不是静态类型的,所以那里的元组更像是固定大小的集合。 Scala不是这样,元组的每个元素都有不同的类型。 Scala中的元组与Python中的用法不同。