首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >=>、()=>和Unit=>之间的区别是什么

=>、()=>和Unit=>之间的区别是什么
EN

Stack Overflow用户
提问于 2010-12-28 10:14:59
回答 4查看 27.5K关注 0票数 156

我试图表示一个不带参数、不返回值的函数(如果您一定要知道,我正在用JavaScript模拟setTimeout函数)。

代码语言:javascript
复制
case class Scheduled(time : Int, callback :  => Unit)

不能编译,因为“` `val‘参数可能不是按名称调用的”

代码语言:javascript
复制
case class Scheduled(time : Int, callback :  () => Unit)  

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

代码语言:javascript
复制
Scheduled(40, { println("x") } )

我必须这么做

代码语言:javascript
复制
Scheduled(40, { () => println("x") } )      

同样有效的是

代码语言:javascript
复制
class Scheduled(time : Int, callback :  Unit => Unit)

而是以一种更不明智的方式调用的

代码语言:javascript
复制
 Scheduled(40, { x : Unit => println("x") } )

(类型为Unit的变量是什么?)当然,我想要的是一个构造函数,它可以像调用普通函数一样被调用:

代码语言:javascript
复制
 Scheduled(40, println("x") )

把奶瓶给宝宝!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-12-28 19:32:37

Call-by-Name:=>类型

=> Type表示call-by-name,这是可以传递的many ways参数之一。如果您不熟悉它们,我建议您花一些时间阅读wikipedia文章,尽管现在它主要是按值调用和按引用调用。

它的意思是传递的内容将替换函数中的值名。例如,以此函数为例:

代码语言:javascript
复制
def f(x: => Int) = x * x

如果我这样称呼它

代码语言:javascript
复制
var y = 0
f { y += 1; y }

然后,代码将像这样执行

代码语言:javascript
复制
{ y += 1; y } * { y += 1; y }

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

还有一些与call-by-name相关的其他要点,我将在解释完其他两个之后再谈到。

0参数函数:() =>类型

语法() => Type代表Function0的类型。也就是说,一个不带参数并返回一些东西的函数。比方说,这相当于调用方法size() --它不接受任何参数并返回一个数字。

然而,有趣的是,这种语法与匿名函数文本的语法非常相似,这是造成一些混淆的原因。例如,

代码语言:javascript
复制
() => println("I'm an anonymous function")

是一个参数为0的匿名函数文本,其类型为

代码语言:javascript
复制
() => Unit

所以我们可以这样写:

代码语言:javascript
复制
val f: () => Unit = () => println("I'm an anonymous function")

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

单位=>类型

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

例如,考虑以下内容:

代码语言:javascript
复制
def f(x: Unit) = ...

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

代码语言:javascript
复制
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度函数来说也存在,对于按名称调用也存在。换句话说,认为,因为

代码语言:javascript
复制
() => { println("Hi!") }

() => Unit的文字,则

代码语言:javascript
复制
{ println("Hi!") }

将是=> Unit的文字。事实并非如此。这是一段代码,而不是文字。

另一个造成混淆的原因是Unit类型的值被写成(),这看起来像一个0参数列表(但它不是)。

票数 244
EN

Stack Overflow用户

发布于 2010-12-28 10:49:45

代码语言:javascript
复制
case class Scheduled(time : Int, callback :  => Unit)

case修饰符对构造函数的每个参数进行隐式val。因此(正如有人指出的那样),如果您删除了case,则可以使用call-by-name参数。编译器可能无论如何都会允许它,但如果它创建了val callback而不是变形为lazy val callback,可能会让人们感到惊讶。

当您现在更改为callback: () => Unit时,您的用例只接受一个函数,而不是一个按名称调用的参数。显然,函数可以存储在val callback中,所以没有问题。

获得所需内容(Scheduled(40, println("x") ),其中按名称调用参数用于传递lambda)的最简单方法可能是跳过case,显式地创建最初无法获得的apply

代码语言:javascript
复制
class Scheduled(val time: Int, val callback: () => Unit) {
    def doit = callback()
}

object Scheduled {
    def apply(time: Int, callback: => Unit) =
        new Scheduled(time, { () => callback })
}

使用中:

代码语言:javascript
复制
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190

scala> Scheduled(1234, println("x")).doit
x
票数 39
EN

Stack Overflow用户

发布于 2018-09-15 04:55:15

在这个问题中,您想要在JavaScript中模拟SetTimeOut函数。根据前面的答案,我编写了以下代码:

代码语言:javascript
复制
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中,我们可以得到如下内容:

代码语言:javascript
复制
scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4543228

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档