带有惰性"by-name"参数的参数列表("*")?

nai*_*rbv 2 scala optional-parameters callbyname

我可以:

scala> def foo( f: => String) = println(f)
foo: (f: => String)Unit
Run Code Online (Sandbox Code Playgroud)

我可以:

scala> def foo( f: String*) = f.map(println)
foo: (f: String*)Seq[Unit]
Run Code Online (Sandbox Code Playgroud)

但我不能:

scala> def foo( f: =>String* ) = f.map(println)
<console>:1: error: ')' expected but identifier found.
       def foo( f: =>String* ) = f.map(println)
                       ^
Run Code Online (Sandbox Code Playgroud)

也不

scala> def foo( f: (=>String)* ) = f.map(println)
<console>:1: error: no by-name parameter type allowed here
       def foo( f: (=>String)* ) = f.map(println)
                ^
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以做我想要的吗?为什么不允许这样做?

Rég*_*les 6

=>意味着参数按名称传递.你所尝试的是不允许的,因为=>String它不是一个真正的类型(而不是说()=>String),你不能做一个Array[=>String].鉴于变量参数x: T*在引擎盖下处理为包含所有参数值的数组(如x: Array[T]),这就是为什么不能创建Array[=>String](没有意义)的原因也意味着f: (=>String)*无法使用可变参数.

使用一个小的包装类可以解决这个问题:

implicit class ByName[T]( getValue: => T ) extends Proxy {
  def apply(): T = getValue
  def self = apply()
}
Run Code Online (Sandbox Code Playgroud)

然后更改方法的签名,如下所示:

def foo( fs: ByName[String]* )
Run Code Online (Sandbox Code Playgroud)

使用多个参数调用方法时,所有参数都将隐式包装到ByName实例中,然后您可以调用apply以获取actal值:

def foo( fs: ByName[String]* ) = fs foreach { f => println( f() ) }
Run Code Online (Sandbox Code Playgroud)

鉴于这可以ByName扩展Proxy到简单的事情,如调用toString或测试相等,你甚至不必调用apply.因此你可以简单地做:

def foo( fs: ByName[String]* ) = f foreach println
Run Code Online (Sandbox Code Playgroud)