【问题标题】:What is the difference between different function creations不同功能创建有什么区别
【发布时间】:2014-10-06 00:44:24
【问题描述】:

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

how to allow passing in a => AnyRef function and call that function

我一直在尝试创建不同的函数,坦率地说,我在创建 => 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 之前调用该函数(这是在我的另一个线程中,是一个单独的问题)。

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

谢谢, 院长

【问题讨论】:

    标签: scala scala-2.9


    【解决方案1】:

    如果你写了这个它会起作用:

    log2.debugLazyTest2(function())
    

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

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

    【讨论】:

    • 这很棒。我没有意识到这是按名称的语法,并认为它是在传递一个函数。现在这为我解决了问题......非常感谢!!!!
    【解决方案2】:

    考虑以下代码:

    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] 的实例传递给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()
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 2012-02-17
      • 2019-08-23
      相关资源
      最近更新 更多