Scala通过名称混淆呼叫

Dan*_*ain 6 scala

我正在使用REPL通过名称示例进行一些调用,并在Eclipse中运行相同的示例.

以下是Eclipse中的内容:
场景1:

val funct = {println("Calling funct")}
takesFunct(funct)

def takesFunct(f: => Unit)
{
   val b = f
}
Run Code Online (Sandbox Code Playgroud)

输出是:调用函数

场景2:
方法takeFunct保持不变

takesFunct({println("Calling funct")}
Run Code Online (Sandbox Code Playgroud)

输出是:
调用本功能
调用本功能

Scala REPL场景1:

scala> def takesFunct(f: => Unit)
{
  val b = f
}
takesFunct: (f: => Unit)Unit

scala> val funct = {println("Calling funct")}
Calling funct
funct: Unit = ()

scala> takesFunct(funct)
// No Output
Run Code Online (Sandbox Code Playgroud)

场景2与上面定义的方法相同

scala> takesFunct({println("Calling funct")}
Calling funct
Run Code Online (Sandbox Code Playgroud)

两个问题
1)为什么Eclipse的输出与REPL不同?
2)传球有什么区别

val funct = {...}
takesFunct(funct)
Run Code Online (Sandbox Code Playgroud)

而不是

takesFunct({...})
Run Code Online (Sandbox Code Playgroud)

Y.H*_*ong 9

在@ IttayD回答后更新:

Eclipse上的场景1是正确的,你会在下面看到原因.场景2显然是一个Eclipse错误.Eclipse上的ScalaIDE因其破碎而闻名.我不相信(或使用它).如果必须,请使用Intellij IDEA的Scala插件.

你的两个问题的答案是,{}是一个返回它的最后一个语句的返回类型的块.它与Scheme (begin)或Common Lisp 完全相同(progn).当你有:

scala> def takesFunct(f: => Unit)
{
  val b = f
}
takesFunct: (f: => Unit)Unit

scala> val funct = {println("Calling funct")}
Calling funct
funct: Unit = ()

scala> takesFunct(funct)
// No Output
Run Code Online (Sandbox Code Playgroud)

funct已经对RHS进行了热切评估,并将()类型值返回Unit到funct.将已计算的值应用于按名称调用的函数并在正文中使用它不会导致重新评估,因为该值已经是叶子.

进一步更新:

def takesFunct(f: => Unit)
Run Code Online (Sandbox Code Playgroud)

具有与...基本相同的语义

def takesFunct(f: () => Unit)
Run Code Online (Sandbox Code Playgroud)

在某些圈子中称为流式传输或延迟评估.但是有一个主要的区别,就是你调用提供的参数的方式.在后一种情况下,为了从中获取值f,您必须调用它 - 即f().在前一种情况下,f是一个惰性表达式,它在第一次引用时计算为一个值,因此按名称调用.您可以将语法f: => Unit视为一种自动包装您在容器中提供的任何表达式的方法{}.使用时检索其内容如下:

scala> val a = { 1 } // 1 wrapped in {}, and retrieved when assigned to a
a: Int = 1
Run Code Online (Sandbox Code Playgroud)

那么这个怎么样?

scala> takesFunct({println("Calling funct")})
Calling funct
Run Code Online (Sandbox Code Playgroud)

这是因为现在您正在创建一个绑定到函数参数的就地块f,并且仅在您使用它时进行评估val b = f.我们再做一个实验:

scala> takesFunct(println("Calling funct"))
Calling funct
Run Code Online (Sandbox Code Playgroud)

你怎么问?因为println(...)被包裹在一个{}必然的f.引用f检索容器内的值println(...),即值的值():Unit.在前面的例子中,f被绑定{ { println(...) } },这是相同的{ println(...) },所以你得到相同的结果.事实上,你可以{}无限期地嵌套,但仍然会得到同样的东西.唯一的区别是,手动提供{}允许您将多个语句放入其中:

scala> takesFunct({ println("hello"); println("world") })
hello
world
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.