【问题标题】:By-name repeated parameters按名称重复参数
【发布时间】:2011-02-12 00:37:36
【问题描述】:

如何在 Scala 中传递按名称重复的参数?

以下代码无法运行:

scala> def foo(s: (=> String)*) = {
<console>:1: error: no by-name parameter type allowed here
       def foo(s: (=> String)*) = {
                   ^

还有其他方法可以将可变数量的按名称参数传递给方法吗?

【问题讨论】:

标签: scala functional-programming variadic-functions lazy-evaluation


【解决方案1】:

目前不支持重复的按名称参数。

【讨论】:

    【解决方案2】:

    这不是很漂亮,但它允许您通过 varargs 样式传递 byname 参数

    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"))
    

    这会产生

    在 foo 中

    在富 f1 f2

    【讨论】:

    • 看和写肯定不愉快。我继续鼓励人们区分名称参数(使用 thunk 实现,但在逻辑上不同)和用作参数的函数值。方法和函数也是如此。
    • 我认为 Randall 的 cmets 是公平的,以上内容可以通过辅助函数来包装/预处理参数进行改进,例如: def deferred(block: => String) = () = > 带有 foo 的块更改为: def foo(s: (() => String)*) 给予,例如: foo(deferred {val a = "apples"; "Green "+apples}, deferred {"Pears"} )
    【解决方案3】:

    如果为漂亮的语法而苦苦挣扎,则可以使用隐式来实现目标。

    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)
    }
    

    打印出来的:

    foo:尚未评估。

    0 1 2

    3 4 5

    嘘:已经评估过

    【讨论】:

      【解决方案4】:

      它适用于 Scala 3:

      scala> def f(i: => Int*): Int = i.sum
      def f(i: => Int*): Int
      
      scala> f(1, 2, 3)
      val res0: Int = 6
      

      【讨论】:

        【解决方案5】:

        你可以写() =&gt; String而不是Unit(反正都是一样的)

        【讨论】:

        • 这真的不是“一回事”。在方法中调用和使用它们的语义和语法都不同。
        【解决方案6】:

        感谢 Randall Schulz 提供了很好的单行答案。

        我一直在寻找这种可能性,以便制作一个可以同时运行多个断言的 INVARIANT 工具。然后我想出的解决方案是简单地使用 1..5 个apply 方法,因为这里需要的可变参数的数量是有限的。

        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
        }
        

        我发布此内容是为了展示我认为在“按名称”变量上使用 varargs 的有效用例。如果有更好的名字,欢迎留言。谢谢。

        【讨论】:

          猜你喜欢
          • 2013-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-31
          • 1970-01-01
          • 1970-01-01
          • 2023-04-08
          • 1970-01-01
          相关资源
          最近更新 更多