【问题标题】:By-Name-Parameters for Constructors构造函数的按名称参数
【发布时间】:2010-04-15 16:28:12
【问题描述】:

来自my other question 有没有办法让构造函数工作的按名称参数?我需要一种方法来提供一个在对象内按需/延迟/按名称执行的代码块,并且该代码块必须能够访问类方法,就好像该代码块是该类的一部分一样.

以下测试用例失败:

package test

class ByNameCons(code: => Unit) {

    def exec() = {
        println("pre-code")
        code
        println("post-code")
    }

    def meth() = println("method")

    def exec2(code2: => Unit) = {
        println("pre-code")
        code2
        println("post-code")
    }
}


object ByNameCons {

    def main(args: Array[String]): Unit = {
        val tst = new ByNameCons {
            println("foo")
            meth() // knows meth() as code is part of ByNameCons
        }
        tst.exec() // ByName fails (executed right as constructor)


        println("--------")


        tst.exec2 { // ByName works
            println("foo")
            //meth() // does not know meth() as code is NOT part of ByNameCons
        }       
    }
}

输出:

foo
method
pre-code
post-code
--------
pre-code
foo
post-code

【问题讨论】:

  • 我使用的是 Scala 2.8 nightlies。

标签: scala constructor pass-by-name


【解决方案1】:

这是因为当您制作这样的实例时:

val tst = new ByNameCons {
  ...
}

.. 你实际上是在创建一个匿名类,就像在 java 中一样。 上面的代码是一样的:

val tst = new ByNameCons() { ... }

.. 而按名称传递的正确语法是:

val tst = new ByNameCons( { ... } )

您不能像使用函数一样省略构造函数的括号。

【讨论】:

  • 你能举个例子说明val tst = new ByNameCons( { ... } )的大括号里面会放什么吗?
【解决方案2】:
val tst = new ByNameCons( {
   println("foo")  
} )

认为这样做可能更容易:

object ByNameCons {
  def apply(code: => Unit) = new ByNameCons(code)
}

val tst = ByNameCons { // no "new" here -- can't mix traits either
  println("foo")
}

【讨论】:

  • 但是这两种变体都不是 ByNameCons 的一部分,也不知道 ByNameCons 的方法,所以如果 ByNameCons { def meth() .. }
  • @hotzen 是的。我没有意识到你希望他们成为ByNameCons的一部分。
【解决方案3】:

我不知道为什么,但似乎在创建类时使用 {} 或 () 会改变行为。使用以下类,

class Coder(code: => Unit) {
  def exec = { 
    println("before")
    code
    println("after")}
  }
}

scala> val brackets = new Coder {println("testing")}
testing
brackets: Coder = $anon$1@1af7a03
scala> brackets exec
before
after

现在,如果以另一种方式定义,

scala> val parens = new Coder(println("testing"))
parens: Coder = Coder@dca3ed
scala> parens exec
before
testing
after

根据需要。似乎在第一种表示法中,编译器将括号解释为要计算为 Unit 的块,而不是一个匿名函数,该函数在调用时计算为 Unit

FWIW,使用 ({ ... }) 也可以正常工作。

【讨论】:

  • 与 Daniel 的帖子中的问题相同,代码不是 Class 的一部分,因此无法访问 Coder 的方法。
猜你喜欢
  • 2014-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 2021-05-31
  • 2015-06-23
相关资源
最近更新 更多