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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:41:31  来源:igfitidea点击:

What's the difference between => , ()=>, and Unit=>

scala

提问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)