=> 和有什么区别? 、()=>、单位=>

发布于 2024-10-09 05:49:47 字数 801 浏览 1 评论 0原文

我试图表示一个不带参数且不返回任何值的函数(如果您必须知道的话,我正在用 JavaScript 模拟 setTimeout 函数。)

case class Scheduled(time : Int, callback :  => Unit)

无法编译,说“‘val’参数可能不会被调用-name"

case class Scheduled(time : Int, callback :  () => Unit)  

编译,但必须奇怪地调用,而不是

Scheduled(40, { println("x") } )

我必须这样做

Scheduled(40, { () => println("x") } )      

什么也有效,

class Scheduled(time : Int, callback :  Unit => Unit)

但以一种甚至不太明智的方式调用

 Scheduled(40, { x : Unit => println("x") } )

(Unit 类型的变量会是什么?)我 Want 当然是一个构造函数,可以按照我调用它的方式调用它(如果它是一个普通函数):

 Scheduled(40, println("x") )

给宝宝他的瓶子!

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.)

case class Scheduled(time : Int, callback :  => Unit)

doesn't compile, saying " `val' parameters may not be call-by-name"

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 want of course is a constructor that can be invoke the way I would invoke it if it were an ordinary function:

 Scheduled(40, println("x") )

Give baby his bottle!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

空城旧梦 2024-10-16 05:49:47

按姓名呼唤: =>输入

=>类型表示法代表按名称调用,这是多种方式之一可以传递参数。如果您不熟悉它们,我建议花一些时间阅读维基百科文章,尽管现在它主要是按值调用和按引用调用。

这意味着传递的内容将替换函数内的值名称。例如,采用这个函数:

def f(x: => Int) = x * x

如果我像这样调用它

var y = 0
f { y += 1; y }

那么代码将像这样执行

{ y += 1; y } * { y += 1; y }

虽然这提出了如果存在标识符名称冲突会发生什么的问题。在传统的按名称调用中,会发生一种称为避免捕获替换的机制来避免名称冲突。然而,在 Scala 中,这是以另一种方式实现的,具有相同的结果——参数内的标识符名称不能引用或隐藏被调用函数中的标识符。

还有一些与直呼姓名相关的要点,我将在解释完其他两点之后再谈。

0 元函数: () =>类型

语法 () =>; Type 代表Function0 的类型。也就是说,一个不带参数并返回某些内容的函数。这相当于调用方法 size() ——它不带参数并返回一个数字。

然而有趣的是,这种语法与匿名函数文字的语法非常相似,这导致了一些混乱。例如,

() => println("I'm an anonymous function")

是一个 arity 0 的匿名函数字面量,其 type

() => Unit

所以我们可以这样写:

val f: () => Unit = () => println("I'm an anonymous function")

但是,重要的是不要将类型与值混淆。

单位=>类型

这实际上只是一个Function1,其第一个参数的类型为Unit。其他编写方式为 (Unit) =>类型Function1[单位,类型]。问题是……这不太可能是人们想要的。 Unit 类型的主要目的是指示一个人们不感兴趣的值,因此接收该值没有意义。

例如,考虑一下,

def f(x: Unit) = ...

人们可以用 x 做什么?它只能有一个值,因此不需要接收它。一种可能的用途是链接返回 Unit 的函数:

val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g

因为 andThen 仅在 Function1 上定义,并且我们链接的函数返回 Unit,我们必须将它们定义为 Function1[Unit, Unit] 类型才能链接它们。

混乱的来源

第一个混乱的来源是认为 0 元函数中存在的类型和文字之间的相似性也存在于按名称调用中。换句话说,认为,because

() => { println("Hi!") }

() => 的文字。 Unit 则将

{ println("Hi!") }

=> 的文字单位。它不是。这是一个代码块,而不是文字。

另一个令人困惑的来源是 Unit 类型的 value 被写成 (),它看起来像一个 0 元参数列表(但事实并非如此) 。

Call-by-Name: => Type

The => Type notation stands for call-by-name, which is one of the many ways parameters 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.

What it means is that what is passed is substituted for 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.

There are some other points related to call-by-name that I'll speak of after explaining the other two.

0-arity Functions: () => Type

The syntax () => Type stands 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.

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 type is

() => 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) => Type or Function1[Unit, Type]. The thing is... this is unlikely to ever be what one wants. The Unit type's main purpose is indicating a value one is not interested in, so doesn't make sense to receive that value.

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:

val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g

Because andThen is 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.

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

() => { println("Hi!") }

is a literal for () => Unit, then

{ println("Hi!") }

would be a literal for => Unit. It is not. That is a block of code, not a literal.

Another source of confusion is that Unit type's value is written (), which looks like a 0-arity parameter list (but it is not).

初雪 2024-10-16 05:49:47
case class Scheduled(time : Int, callback :  => Unit)

case 修饰符使构造函数的每个参数隐含 val 。因此(正如有人指出的)如果您删除 case 您可以使用按名称调用参数。无论如何,编译器可能会允许它,但如果它创建 val 回调 而不是转变为 lazy val 回调,人们可能会感到惊讶。

当您更改为 callback: () =>;现在你的案例只需要一个函数而不是一个按名称调用的参数。显然该函数可以存储在 valcallback 中,所以没有问题。

获得所需内容的最简单方法(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 })
}

在使用中:

scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190

scala> Scheduled(1234, println("x")).doit
x
case class Scheduled(time : Int, callback :  => Unit)

The case modifier makes implicit val out of each argument to the constructor. Hence (as someone noted) if you remove case you can use a call-by-name parameter. The compiler could probably allow it anyway, but it might surprise people if it created val callback instead of morphing into lazy val callback.

When you change to callback: () => Unit now your case just takes a function rather than a call-by-name parameter. Obviously the function can be stored in val callback so there's no problem.

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 case and explicitly create the apply that you couldn't get in the first place:

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
兮颜 2024-10-16 05:49:47

在问题中,您想在 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
  }
}

在REPL中,我们可以得到这样的结果:

scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b

我们的模拟与SetTimeOut的行为并不完全相同,因为我们的模拟是阻塞函数,但SetTimeOut是非阻塞的。

In the question, you want to simulate SetTimeOut function in JavaScript. Based on previous answers, I write following code:

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:

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.

如若梦似彩虹 2024-10-16 05:49:47

我这样做(只是不想打破应用):

case class Thing[A](..., lazy: () => A) {}
object Thing {
  def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}

并调用它

Thing.of(..., your_value)

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文