【问题标题】:Scala - difference between function definition and function literal with no argumentsScala - 函数定义和没有参数的函数文字之间的区别
【发布时间】:2020-06-17 00:26:12
【问题描述】:
scala> def nextOption = if (util.Random.nextInt > 0) Some(1) else None
nextOption: Option[Int]

scala> nextOption
res1: Option[Int] = Some(1)

scala> nextOption
res3: Option[Int] = None

尝试学习scala,下面执行的代码几个问题:
1. nextOption 定义的右边部分是否考虑了函数字面量?
2. 如果使用 'val' 关键字而不是 'def' 定义它会改变吗?
3. 为什么 nextOption 类型是 Option[Int] 而不是函数? ( ()=>Option[Int] )
4. 在这段代码中添加括号或括号会改变它的类型/值吗?
5. nextOption 和'() => if (......) some(1) Else None'之类的有什么区别

【问题讨论】:

    标签: scala


    【解决方案1】:
    1. 为什么nextOption 键入Option[Int] 而不是函数() => Option[Int]

    我认为混淆源于 REPL 打印 method typesparameterless methods 的方式。考虑如果我们添加空参数列表()会发生什么

    scala> def nextOption() = if (util.Random.nextInt > 0) Some(1) else None
    nextOption: ()Option[Int]
    

    注意现在方法类型如何打印为()Option[Int],而不是熟悉的() => Option[Int]。恕我直言,如果 REPL 会像这样打印无参数方法的方法类型,它可能不会那么混乱

    => Option[Int]
    

    正如 SLS 中描述的那样

    一种特殊情况是没有任何参数的方法类型。他们是 写在这里=> T。无参数方法名称表达式是 每次引用无参数方法名时重新计算。

    注意方法不是值,方法类型只是编译器内部的东西:

    方法类型不作为值类型存在。如果使用方法名 作为一个值,它的类型被隐式转换为对应的 函数类型。

    我们可以通过 eta 扩展显式地将方法类型转换为函数类型

    scala> nextOption _
    res12: () => Option[Int] = $$Lambda$1218/528012220@37e5111b
    

    【讨论】:

      【解决方案2】:

      按顺序进行:

      1) 不。函数字面量是匿名函数。在这里,您清楚地为您的表达式指定了一个名称。正如您稍后提到的,() => if (......) some(1) Else None 将是一个函数文字。如果您在 REPL 中执行此操作,您将看到它 literally 返回一个函数 :) 函数文字没有名称,您可以将它们分配给值/变量。你可以在这里阅读更多内容:

      What is a function literal in Scala?

      2) 在这种情况下不会有任何区别。如果您要执行匿名函数,则编译器会将其解释为Function0 的实例。它被称为 ETA 扩展,但是我相信这会剥夺您指定泛型类型的能力。更多关于区别here

      3) Scala 允许仅按名称调用零参数的方法,也就是您可以省略括号。因此,当您调用nextOption 时,它会计算函数并返回结果。

      4) 不,它不会。

      5) 如第一种情况所述,这确实是一个匿名函数,您会在 REPL 中看到该函数

      【讨论】:

        【解决方案3】:
        1. nextOption 定义的右侧部分是否被视为函数字面量?

        不,那只是方法体。
        function 文字类似于:(i: Int) => i + 1

        1. 如果使用 'val' 关键字而不是 'def' 来定义它会改变吗?

        如果您只是将def 更改为val,则代码将只执行一次,您将获得一个,而不是方法功能

        1. 为什么 nextOption 类型是 Option[Int] 而不是函数? ( ()=>Option[Int] )

        那不是nextOption的类型,而是方法执行后返回值的类型。

        1. 在此代码中添加圆括号或方括号会改变其类型/值吗?

        不知道你到底是什么意思,请编辑问题,我会编辑答案。

        1. nextOption 和类似 '() => if (......) some(1) Else None' 之间有什么区别

        如果你这样做:

        val foo = () => if (util.Random.nextInt > 0) Some(1) else None
        

        然后你有效地创建了一个函数,你可以像这样使用它:

        foo()
        // res: Option[Int] = None
        

        这可能会有所帮助:Difference between method and function in Scala

        【讨论】:

        • 对于#2,虽然您确实得到了一个值,但 ETA 扩展不会将该值转换为 Function0 吗?
        • @sinanspd 为什么?我看不出有任何理由。但老实说,我不是 ETA 扩展方面的专家,但 AFAIK 仅在您需要功能时才会发生,而在这种情况下不会发生。
        • 我认为你是对的。我相信如果右侧是匿名函数,它会生效,但在这种情况下,它是一个简单的表达式。我的错。
        【解决方案4】:
        1. 不,它不是函数字面量,它是一种方法。函数文字看起来像

          val nextOptionF = () => if (util.Random.nextInt > 0) Some(1) else None

        您可以通过以下方式将您的方法转换为函数

        val nextOptionF = nextOption _ 
        
        1. 如果您只是从def 更改为val,nextOption 将变为Option[Int]
        2. 当您执行 nextOption 时,该方法被执行,因为您没有在方法的定义中添加参数。如果你添加了参数:
            def nextOption() = if (util.Random.nextInt > 0) Some(1) else None
        
        
            nextOption
            res1: Option[Int] = Some(1)
        
        1. 已经回复
        2. 这将返回一个函数字面量

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-26
          • 1970-01-01
          • 1970-01-01
          • 2022-01-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多