Подтвердить что ты не робот

Почему нет шаблона Tuple1 для одноэлементных кортежей в Scala?

Python имеет (1,) для одного элемента кортежа. В Scala, (1,2) работает для Tuple2(1,2), но мы должны использовать Tuple1(1), чтобы получить один элемент tuple. Это может показаться небольшой проблемой, но разработка API-интерфейсов, которые ожидают, что Продукт станет больно для пользователей, которые передают отдельные элементы, поскольку они должны писать Tuple1 (1).

Возможно, это небольшая проблема, но основной точкой продаж Scala является более типизация с меньшим набором символов. Но в этом случае кажется, что он больше набирает текст при печати. ​​

Скажите, пожалуйста: 1) Я пропустил это и существует в другой форме, или 2) Он будет добавлен в будущую версию языка (и они будут принимать патчи).

4b9b3361

Ответ 1

Вы можете определить неявное преобразование:

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

Неявное преобразование применяется только в том случае, если статический тип аргумента не соответствует типу параметра метода. Предполагая, что ваш метод принимает аргумент Product

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

преобразование будет применяться к непродуктовому значению, но не будет применяться, например, к Tuple2. Предупреждение: все классы case расширяют признак 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)

Ответ 2

Вы могли бы, конечно, добавить неявное преобразование в ваш API:

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

Мне кажется нечетным, что Tuple1.toString содержит конечную запятую:

scala> Tuple1(1)
res0: (Int,) = (1,)

Ответ 3

Python не статически типизирован, поэтому кортежи там больше похожи на коллекции фиксированного размера. Это не относится к Scala, где каждый элемент кортежа имеет отдельный тип. Кортежи, в Scala, не имеют того же вида использования, что и в Python.