0

这个问题与我的另一个问题密切相关(可能会导致我解决那个问题),但绝对不同。

如何允许传入 => AnyRef 函数并调用该函数

我一直在玩不同的函数创建,坦率地说,我在创建 => AnyRef 和 => String 类型的匿名函数时遇到了麻烦。我认为我可以创建 () => AnyRef 和 () => String 类型的函数。

示例 1 我有以下代码

def debugLazyTest2(msg: => String) : Unit = {
  System.out.println(msg)
}

//and client code
  val function: () => String = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest2(function)

但编译错误说 found: () => String 这很有意义,但随后说“required:String”而不是“required:=> String”

这里发生了什么?

示例 2 更奇怪的是,我有这段代码编译,而上面没有编译

def debugLazyTest(msg: => AnyRef) : Unit = {
  System.out.println(msg.toString)
}

//and client code which compiles!!!!
  val function: () => AnyRef = () => {
    executed = true
    "asdf"+executed+" hi there"
  }
  log2.debugLazyTest(function)

这段代码可以编译,尽管它不像我想要的那样工作,因为在调用 toString 之前库似乎无法调用函数(这是在我的另一个线程中,是一个单独的问题)。

关于这里发生了什么的任何想法?

谢谢,院长

4

2 回答 2

3

考虑以下代码:

scala> def test(x: String) = debugLazyTest2(x)
test: (x: String)Unit

如果我们然后运行(在 Scala 2.11.2 中):

:javap test

并修剪一些生成的输出,我们看到以下内容:

  public void test(java.lang.String);
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field .MODULE$:L;
         3: new           #21                 // class $anonfun$test$1
         6: dup
         7: aload_1
         8: invokespecial #23                 // Method $anonfun$test$1."<init>":(Ljava/lang/String;)V
        11: invokevirtual #27                 // Method .debugLazyTest2:(Lscala/Function0;)V
        14: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      15     0  this   L;
               0      15     1     x   Ljava/lang/String;
      LineNumberTable:
        line 8: 0

然后我们考虑签名debugLazyTest2

 public void debugLazyTest2(scala.Function0<java.lang.String>);

关键线是:

         3: new           #21                 // class $anonfun$test$1

如果我正确阅读代码,我们将实例化该类的一个新实例$anonfun$test$1- 并将该新匿名传递Function0[String]debugLazyTest2. 这使得我们的test方法等效于以下内容:

def test(x: String) = debugLazyTest2(new Function0[String] {
    def apply(): String = x
})

Function0[String]当我们考虑传入一个to的实例debugLazyTest2进行相同的转换时,我们得到:

debugLazyTest2(function)

变成:

debugLazyTest2(new Function0[String] {
    def apply(): Function0[String] = function
})

当然,它不会编译,因为apply(): Function0[String]与所需的类型不匹配apply(): String(因此出现错误消息)。

实际上调用函数而不是返回它是有效的:

debugLazyTest2(function())

变成:

debugLazyTest2(new Function0[String] {
    def apply(): String = function()
})
于 2014-08-12T20:18:04.933 回答
3

如果你写这个它会工作:

log2.debugLazyTest2(function())

msg 是一个名称参数,而不是一个函数。您必须传入 String 类型的表达式(或第二个示例中的 AnyRef)

第二个示例可以编译,因为您传入的 () => AnyRef 实际上也是 AnyRef,因为函数是 AnyRef。但随后打印的是函数本身,而不是执行它的结果。

于 2014-08-12T20:23:17.250 回答