Scala中是否有等价于Python列表解包(即“*”)操作符的功能?

26 投票
4 回答
18431 浏览
提问于 2025-04-17 16:49

在Python中,我们有一个叫做星号(“*”或者“解包”)的操作符,它可以帮助我们把一个列表拆开,方便地传递位置参数。举个例子:

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中使用的方法,还有没有更简洁的方式来做到这一点呢?

4 个回答

5

你可以通过使用 shapeless 来接近 Python 的一些功能,

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 的 shapeless 时需要多一些步骤。这是因为 shapeless 在编译时就会检查一些条件,确保在运行时这些条件是满足的(而 Python 则是在运行时检查,如果 args 的大小不对或者类型不对就会出错)……所以在 Scala 中,你必须明确指定你希望 List 里有什么类型(在这个例子中就是确切的三个 Strings),并且要准备好处理那些不符合预期的情况(因为结果会明确是一个 Option 类型的 ThreeValues)。

41

在Scala中没有直接对应的东西。

你能找到的最接近的就是使用 _* ,这个只适用于可变参数的方法。

举个例子,这里有一个可变参数的方法:

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    
4

有一个类似的东西叫做 tupled,它可以把一个需要 n 个参数的函数转换成一个只需要一个 n 元组类型参数的函数。

想了解更多信息,可以看看这个问题:scala 元组拆解

对于数组来说,这种方法就没什么意义了,因为它只适用于那些有多个相同类型参数的函数。

撰写回答