Why is there no Tuple1 Literal for single element tuples in Scala?

后端 未结 3 1138
野趣味
野趣味 2021-01-17 12:31

Python has (1,) for a single element tuple. In Scala, (1,2) works for Tuple2(1,2) but we must use Tuple1(1) to get a sin

3条回答
  •  清酒与你
    2021-01-17 12:42

    You can define an implicit conversion:

    implicit def value2tuple[T](x: T): Tuple1[T] = Tuple1(x)
    

    The implicit conversion will only apply if the argument's static type does not already conform to the method parameter's type. Assuming your method takes a Product argument

    def m(v: Product) = // ...
    

    the conversion will apply to a non-product value but will not apply to a Tuple2, for example. Warning: all case classes extend the Product trait, so the conversion will not apply to them either. Instead, the product elements will be the constructor parameters of the case class.

    Product is the least upper bound of the TupleX classes, but you can use a type class if you want to apply the implicit Tuple1 conversion to all non-tuples:

    // 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 ...
    }
    

    You can use this type class in your API as follows:

    def m[T: Tupleable](v: T) = { 
       val p = implicitly[Tupleable[T]](v) 
       // ... do something with p
    }
    

    If you have your method return the product, you can see how the conversions are being applied:

    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)
    

提交回复
热议问题