开发者

By-name repeated parameters

开发者 https://www.devze.com 2022-12-27 21:23 出处:网络
How to pass by-name repeated parameters in Scala? The following code fails to work: scala> def foo(s: (=> String)*) = {

How to pass by-name repeated parameters in Scala?

The following code fails to work:

scala> def foo(s: (=> String)*) = {
<console>:1: 开发者_开发知识库error: no by-name parameter type allowed here
       def foo(s: (=> String)*) = {
                   ^

Is there any other way I could pass a variable number of by name parameters to the method?


Repeated by-name parameters are not currently supported.


This isn't very pretty but it allows you to pass byname parameters varargs style

def printAndReturn(s: String) = {
  println(s)
  s
}

def foo(s: (Unit => String)*) {
  println("\nIn foo")
  s foreach {_()}  // Or whatever you want ...
}

foo()

foo((Unit) => printAndReturn("f1"),
    (Unit) => printAndReturn("f2"))

This produces

In foo

In foo f1 f2


If struggling for nice syntax the goal can be achieved using implicits.

implicit def arg2func(arg: ⇒ Byname): (() => Byname) = () ⇒ arg

def foo(params: (() ⇒ Byname)*): Unit = {
    println("foo: not yet evaluated.")
    params.foreach(_())
}

def boo(params: Byname*): Unit = {
    println("boo: already evaluated")
}

foo(Byname(0), Byname(1), Byname(2))
println()
boo(Byname(3), Byname(4), Byname(5))

case class Byname(n: Int) {
    println(n)
}

That prints:

foo: not yet evaluated.

0 1 2

3 4 5

boo: already evaluated


It works in Scala 3:

scala> def f(i: => Int*): Int = i.sum
def f(i: => Int*): Int

scala> f(1, 2, 3)
val res0: Int = 6


You can write () => String instead of Unit (it's the same thing anyway)


Thanks Randall Schulz on the good one-line answer.

I was looking for this possibility in order to make an INVARIANT tool that would run multiple asserts together. The solution I then came up with is to simply have 1..5 apply methods, since the number of varargs needed here is finite.

object INVARIANT {
  def apply = {}
  def apply( conds: => Boolean * ) = {    // DOES NOT COMPILE
    conds.foreach( assert(_) )
  }
}

object TestX extends App {

  class A {
    println("A body")
    INVARIANT( true )
  }

  class B extends A {
    println("B body")
    INVARIANT( true, false )  
  }

  new B
}

I posted this to show what I believe is a valid use case for varargs on 'by-name' variables. If there is a better name, please leave a comment. Thanks.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号