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

Существует ли Scala эквивалент оператора распаковки списка python (a.k.a. "*" )?

В Python у нас есть оператор star (или "*" или "unpack" ), который позволяет нам распаковать список для удобного использования при передаче позиционных аргументов. Например:

range(3, 6)
args = [3, 6]
# invokes range(3, 6)
range(*args)

В этом конкретном примере он не сохраняет много типизации, так как range принимает только два аргумента. Но вы можете себе представить, что если было больше аргументов для range или если args было прочитано из источника ввода, возвращено из другой функции и т.д., Тогда это может пригодиться.

В Scala я не смог найти эквивалент. Рассмотрим следующие команды, выполняемые в интерактивном сеансе Scala:

case class ThreeValues(one: String, two: String, three: String)

//works fine
val x = ThreeValues("1","2","3")

val argList = List("one","two","three")

//also works
val y = ThreeValues(argList(0), argList(1), argList(2))

//doesn't work, obviously
val z = ThreeValues(*argList)

Есть ли более краткий способ сделать это, кроме метода, используемого в val y?

4b9b3361

Ответ 1

Есть что-то подобное для функций: tupled Он преобразует функцию, которая принимает n параметров в функцию, которая принимает один аргумент типа n-tuple.

См. этот вопрос для получения дополнительной информации: scala распаковка tuple

Такой метод для массивов не имеет большого смысла, поскольку он будет работать только с функциями с несколькими аргументами одного и того же типа.

Ответ 2

В scala нет прямого эквивалента. Самое близкое, что вы найдете, это использование _*, которое работает только с методами vararg. Например, здесь приведен пример метода vararg:

def hello( names: String*) {
  println( "Hello " + names.mkString(" and " ) )
}

который может использоваться с любым количеством аргументов:

scala> hello()
Hello
scala> hello("elwood")
Hello elwood
scala> hello("elwood", "jake")
Hello elwood and jake

Теперь, если у вас есть список строк и вы хотите передать их этому методу, способ распаковать его - через _*:

scala> val names = List("john", "paul", "george", "ringo")
names: List[String] = List(john, paul, george, ringo)
scala> hello( names: _* )
Hello john and paul and george and ringo    

Ответ 3

Вы можете получить некоторый путь к Python, используя shapeless,

Welcome to Scala version 2.11.0-20130208-073607-ce32c1af46 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import shapeless._
import shapeless._

scala> import Traversables._
import Traversables._

scala> case class ThreeValues(one: String, two: String, three: String)
defined class ThreeValues

scala> val argList = List("one","two","three")
argList: List[String] = List(one, two, three)

scala> argList.toHList[String :: String :: String :: HNil].map(_.tupled).map(ThreeValues.tupled)
res0: Option[ThreeValues] = Some(ThreeValues(one,two,three))

Как вы можете видеть, требуется немного больше церемоний в Scala с бесформенным. Это связано с тем, что бесформенный налагает ограничения времени компиляции, которые гарантируются во время выполнения (в отличие от python, который не будет работать во время выполнения, если args - неправильный размер или содержит элементы неправильного типа)... вместо этого вы вынуждены чтобы указать тип, который вы ожидаете от List (в данном случае ровно три Strings), и быть готовым обработать случай, когда это ожидание не выполняется (потому что результат явно является Option of ThreeValues).