在Scala中调用带有和不带括号的无参数函数以不同的方式执行

时间:2015-02-28 13:16:11

标签: scala currying

我有以下Currying函数声明:

def logString(count: Int)(fun:() => Unit) {
  for (n <- 1 to count) { fun }
}

我用这种方式调用这个函数:

logString(3) { () => print("I") }

结果没什么 - 只是没有输出。

然后我只需在&#34; fun&#34;之后添加括号函数调用,在Currying函数声明体内:

def logString(count: Int)(fun:() => Unit) {
  for (n <- 1 to count) { fun() }
}

结果成为预期的结果:

III

这是一些Scala错误,还是在学习Scala时我错过了一些规则?

我知道当你声明这样的函数时有规则:     def myFun = 1 我们不能用括号调用它 - 编译失败。 但是在调用带括号和不带括号的函数时有不同的结果似乎更像是一个错误。

我是对的还是我想念Scala?

4 个答案:

答案 0 :(得分:6)

查看fun的类型,它是fun: () => Unit。您可以认为这意味着当您使用()调用它时,您会获得Unit作为回报。如果没有明确地调用它,fun函数称为值,而不是调用它的结果。这是高阶函数概念的本质。

如果它有类型fun: => Unit,只需提及fun就会导致它被执行,在这种情况下,无法将该函数作为值引用。

答案 1 :(得分:4)

当你有这样的宣言时

val x = 10

这是一个价值定义。值x可以是整数,就像在这种情况下一样, 但它也可以是一种功能。

val y = () => println("i'm a function")

然而无论如何,如果你在没有括号的情况下调用它,就不会发生任何事情。

scala> val x = 10
x: Int = 10

scala> val y = () => println("i'm a function")
y: () => Unit = <function0>

scala> x
res0: Int = 10

scala> y
res1: () => Unit = <function0>

如果你有这样的功能定义:

def z() = println("i'm a function def")

然后你可以省略parenthisis并在没有它的情况下调用它。

scala> def z() = println("i'm a function def")
z: ()Unit

scala> z
i'm a function def

在您的情况下,fun就像一个值定义(它是value parameter)。

当Scala评估您的for表达式时,它会对fun无效。

就像上面示例中的y vs y()一样。

答案 2 :(得分:1)

在第一个例子中,函数fun没有被调用,它只是坐在那里。添加括号会导致评估传入函数。

答案 3 :(得分:0)

我只想根据上面非常有用的答案和一些其他研究分享我总结的信息。也可能对别人有帮助。 可以在Scala中以两种方式声明函数:   - &#34;按名称调用&#34; - 它们在字节代码中以简单的方式表示为普通的Java函数。   - &#34;按值调用&#34; - 从Scala的抽象观点来看,它们存储在变量中。实际上在字节代码中,它们存储在实现单抽象方法接口(SAM)的类中,并作为方法参数或普通变量传递。

当我们调用不带参数的&#34;按名称调用&#34; 函数时,无论我们如何使用或不使用括号调用它,它总是被执行。 所以现在 myFunction myFunction()是一样的。 当我们调用不带参数的&#34;按值调用&#34; 函数时,我们有两种情况:   - 当我们之后没有括号 - myFunction 时 - 我们只是引用指向函数的变量而不执行函数本身。   - 当我们有括号 - myFunction()时 - 我们实际调用(执行)函数。

声明功能的不同方式:

def myFunction = 5 * 5

这是按名称调用功能。这样声明在调用它时不允许使用括号。所以调用 myFunction()将无法编译。这样称呼: myFunction

def myFunction() = 5 * 5

这是按名称调用功能。可以使用和不使用括号调用函数 - 效果是相同的。所以 myFunction myFunction()是一样的。

def myFunction = () => 5 * 5

这是按值调用功能(即使声明为 def 而不是 val )。当使用括号调用它时 - myFunction() - 执行函数时,在没有括号的情况下调用它时 - myFunction - 函数未执行 - 只是提到了val持有它。< / p>

同样,如果我们将函数声明为其他函数的参数:

def enclosingFunc(myFunction: => Void)

这是按名称调用功能。在封闭函数内部,只有在没有括号的情况下调用它才会执行 - myFunction 。括号 - myFunction() - 将无法编译。

在这种情况下,可以通过以下方式调用 enclosingFunc

enclosingFunc(n = 1; n +=1)


def enclosingFunc(myFunction: () => Int)

这是按值调用功能。重要的是我们如何在封闭函数体中调用它。如果没有括号调用它 - myFunction - 它将不会执行,但我们只是引用它的对象。如果用括号调用它 - myFunction() - 它将被调用并执行。

在这种情况下, enclosingFunc 只能以这种方式调用:

enclosingFunc( () => n = 1; n +=1)