scala => 、 ()=> 和 Unit=> 之间有什么区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4543228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between => , ()=>, and Unit=>
提问by Malvolio
I'm trying to represent a function that takes no arguments and returns no value (I'm simulating the setTimeout function in JavaScript, if you must know.)
我正在尝试表示一个不接受任何参数且不返回任何值的函数(如果您必须知道,我正在模拟 JavaScript 中的 setTimeout 函数。)
case class Scheduled(time : Int, callback : => Unit)
doesn't compile, saying " `val' parameters may not be call-by-name"
不编译,说“`val' 参数可能不是按名称调用的”
case class Scheduled(time : Int, callback : () => Unit)
compiles, but has to be invoked strangely, instead of
编译,但必须奇怪地调用,而不是
Scheduled(40, { println("x") } )
I have to do this
我必须这样做
Scheduled(40, { () => println("x") } )
What also works is
同样有效的是
class Scheduled(time : Int, callback : Unit => Unit)
but is invoked in an even-less-sensible way
但以一种更不明智的方式被调用
Scheduled(40, { x : Unit => println("x") } )
(What would a variable of type Unit be?) What I wantof course is a constructor that can be invoke the way I would invoke it if it were an ordinary function:
(Unit 类型的变量是什么?)当然,我想要的是一个构造函数,它可以像调用普通函数一样调用它:
Scheduled(40, println("x") )
Give baby his bottle!
给宝宝他的奶瓶!
回答by Daniel C. Sobral
Call-by-Name: => Type
按名称调用:=> 类型
The => Typenotation stands for call-by-name, which is one of the many waysparameters can be passed. If you aren't familiar with them, I recommend taking some time to read that wikipedia article, even though nowadays it is mostly call-by-value and call-by-reference.
该=> Type符号代表按名称调用,这是传递参数的多种方式之一。如果您不熟悉它们,我建议您花一些时间阅读维基百科文章,尽管现在它主要是按值调用和按引用调用。
What it means is that what is passed is substitutedfor the value name inside the function. For example, take this function:
这意味着传递的内容被替换为函数内的值名称。以这个函数为例:
def f(x: => Int) = x * x
If I call it like this
如果我这样称呼它
var y = 0
f { y += 1; y }
Then the code will execute like this
然后代码会像这样执行
{ y += 1; y } * { y += 1; y }
Though that raises the point of what happens if there's a identifier name clash. In traditional call-by-name, a mechanism called capture-avoiding substitution takes place to avoid name clashes. In Scala, however, this is implemented in another way with the same result -- identifier names inside the parameter can't refer to or shadow identifiers in the called function.
尽管这提出了如果存在标识符名称冲突会发生什么的问题。在传统的按名称调用中,会发生一种称为避免捕获替换的机制来避免名称冲突。然而,在 Scala 中,这是以另一种方式实现的,结果相同——参数内的标识符名称不能引用或隐藏被调用函数中的标识符。
There are some other points related to call-by-name that I'll speak of after explaining the other two.
在解释了其他两点之后,我将谈到与按名称呼唤相关的其他一些要点。
0-arity Functions: () => Type
0 元函数:() => 类型
The syntax () => Typestands for the type of a Function0. That is, a function which takes no parameters and returns something. This is equivalent to, say, calling the method size()-- it takes no parameters and returns a number.
语法() => Type代表 a 的类型Function0。也就是说,一个不带参数并返回一些东西的函数。这相当于调用该方法size()——它不接受任何参数并返回一个数字。
It is interesting, however, that this syntax is very similar to the syntax for a anonymous function literal, which is the cause for some confusion. For example,
然而,有趣的是,这种语法与匿名函数字面量的语法非常相似,这导致了一些混淆。例如,
() => println("I'm an anonymous function")
is an anonymous function literal of arity 0, whose typeis
是一个元数为 0 的匿名函数字面量,其类型为
() => Unit
So we could write:
所以我们可以写:
val f: () => Unit = () => println("I'm an anonymous function")
It is important not to confuse the type with the value, however.
但是,不要将类型与值混淆,这一点很重要。
Unit => Type
单位 => 类型
This is actually just a Function1, whose first parameter is of type Unit. Other ways to write it would be (Unit) => Typeor Function1[Unit, Type]. The thing is... this is unlikely to ever be what one wants. The Unittype's main purpose is indicating a value one is not interested in, so doesn't make sense to receivethat value.
这实际上只是 a Function1,其第一个参数的类型为Unit。其他写法是(Unit) => Typeor Function1[Unit, Type]。问题是……这不太可能是人们想要的。该Unit类型的主要目的是指示一个人不感兴趣的值,因此接收该值没有意义。
Consider, for instance,
考虑,例如,
def f(x: Unit) = ...
What could one possibly do with x? It can only have a single value, so one need not receive it. One possible use would be chaining functions returning Unit:
一个人可能会做x什么?它只能有一个值,因此不需要接收它。一种可能的用途是链接函数返回Unit:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
Because andThenis only defined on Function1, and the functions we are chaining are returning Unit, we had to define them as being of type Function1[Unit, Unit]to be able to chain them.
因为andThen仅在 上定义Function1,并且我们正在链接的函数正在返回Unit,所以我们必须将它们定义为类型Function1[Unit, Unit]才能链接它们。
Sources of Confusion
混乱之源
The first source of confusion is thinking the similarity between type and literal that exists for 0-arity functions also exists for call-by-name. In other words, thinking that, because
混淆的第一个来源是认为存在于 0 元函数的类型和文字之间的相似性也存在于按名称调用。换句话说,认为,因为
() => { println("Hi!") }
is a literal for () => Unit, then
是一个字面量 for () => Unit,那么
{ println("Hi!") }
would be a literal for => Unit. It is not. That is a block of code, not a literal.
将是=> Unit. 它不是。那是一段代码,而不是文字。
Another source of confusion is that Unittype's valueis written (), which looks like a 0-arity parameter list (but it is not).
另一个令人困惑的来源是该Unit类型的值是 write (),它看起来像一个 0 元参数列表(但它不是)。
回答by Ben Hymanson
case class Scheduled(time : Int, callback : => Unit)
The casemodifier makes implicit valout of each argument to the constructor. Hence (as someone noted) if you remove caseyou can use a call-by-name parameter. The compiler could probably allow it anyway, but it might surprise people if it created val callbackinstead of morphing into lazy val callback.
该case修改使隐性val每个参数的构造出来。因此(正如有人指出的那样)如果您删除case您可以使用按名称调用参数。无论如何编译器可能会允许它,但如果它创建val callback而不是变形为lazy val callback.
When you change to callback: () => Unitnow your case just takes a function rather than a call-by-name parameter. Obviously the function can be stored in val callbackso there's no problem.
当您更改为callback: () => Unit现在时,您的案例只需要一个函数而不是一个按名称调用的参数。显然该函数可以存储在其中,val callback所以没有问题。
The easiest way to get what you want (Scheduled(40, println("x") )where a call-by-name parameter is used to pass a lambda) is probably to skip the caseand explicitly create the applythat you couldn't get in the first place:
获得所需内容的最简单方法(Scheduled(40, println("x") )使用按名称调用参数传递 lambda 的地方)可能是跳过case并显式创建apply您首先无法获得的:
class Scheduled(val time: Int, val callback: () => Unit) {
def doit = callback()
}
object Scheduled {
def apply(time: Int, callback: => Unit) =
new Scheduled(time, { () => callback })
}
In use:
正在使用:
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190
scala> Scheduled(1234, println("x")).doit
x
回答by Jeff Xu
In the question, you want to simulate SetTimeOut function in JavaScript. Based on previous answers, I write following code:
在这个问题中,您想在 JavaScript 中模拟 SetTimeOut 函数。根据以前的答案,我编写了以下代码:
class Scheduled(time: Int, cb: => Unit) {
private def runCb = cb
}
object Scheduled {
def apply(time: Int, cb: => Unit) = {
val instance = new Scheduled(time, cb)
Thread.sleep(time*1000)
instance.runCb
}
}
In REPL, we can get something like this:
在 REPL 中,我们可以得到这样的结果:
scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b
Our simulation doesn't behave exactly the same as SetTimeOut, because our simulation is blocking function, but SetTimeOut is non-blocking.
我们的模拟与 SetTimeOut 的行为并不完全相同,因为我们的模拟是阻塞函数,而 SetTimeOut 是非阻塞函数。
回答by Alexey Rykhalskiy
I do it this way (just don't want to break apply):
我这样做(只是不想打破申请):
case class Thing[A](..., lazy: () => A) {}
object Thing {
def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}
and call it
并称之为
Thing.of(..., your_value)

