问题
I can:
scala> def foo( f: => String) = println(f)
foo: (f: => String)Unit
and I can:
scala> def foo( f: String*) = f.map(println)
foo: (f: String*)Seq[Unit]
but I can't:
scala> def foo( f: =>String* ) = f.map(println)
<console>:1: error: ')' expected but identifier found.
def foo( f: =>String* ) = f.map(println)
^
nor
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)
^
Is there some other way to do what I want? Why isn't this allowed?
回答1:
Here the =>
means that the parameter is passed by name. What you have tried isn't allowed simply because =>String
is not an actual type (as opposed to say ()=>String
) and you cannot make an Array[=>String]
. Given that a variadic parameter x: T*
is under the hood handled as an array containing all the parameter's values (as in x: Array[T]
), this is the reason why not being able to create a Array[=>String]
(which does not make sense) also means that a variadic parameter f: (=>String)*
is not possible.
This problem can be worked around using a little wrapper class:
implicit class ByName[T]( getValue: => T ) extends Proxy {
def apply(): T = getValue
def self = apply()
}
Then change the signature of your method like so:
def foo( fs: ByName[String]* )
When calling your method with multiple arguments, all the arguments will be implicitly wrapped into a ByName
instance, and then you can call apply
to get the actal value:
def foo( fs: ByName[String]* ) = fs foreach { f => println( f() ) }
Given that ByName
extends Proxy
for simple things such as calling toString
or testing equality you don't even have to call apply
. Thus you can simply do:
def foo( fs: ByName[String]* ) = f foreach println
来源:https://stackoverflow.com/questions/16319796/parameter-list-with-lazy-by-name-parameters