我试图表示一个不带参数的函数并且不返回任何值(我在JavaScript中模拟setTimeout函数,如果你必须知道的话.)
case class Scheduled(time : Int, callback : => Unit)
Run Code Online (Sandbox Code Playgroud)
不编译,说"`val'参数可能不是按名称调用"
case class Scheduled(time : Int, callback : () => Unit)
Run Code Online (Sandbox Code Playgroud)
编译,但必须奇怪地调用,而不是
Scheduled(40, { println("x") } )
Run Code Online (Sandbox Code Playgroud)
我必须这样做
Scheduled(40, { () => println("x") } )
Run Code Online (Sandbox Code Playgroud)
什么也有效
class Scheduled(time : Int, callback : Unit => Unit)
Run Code Online (Sandbox Code Playgroud)
但是以一种更加明智的方式被引用
Scheduled(40, { x : Unit => println("x") } )
Run Code Online (Sandbox Code Playgroud)
(Unit类型的变量是什么?)我当然想要的是一个构造函数,如果它是一个普通的函数,它可以调用我调用它的方式:
Scheduled(40, println("x") )
Run Code Online (Sandbox Code Playgroud)
给宝宝他的瓶子!
Dan*_*ral 227
该=> Type
符号代表的call-by-的名字,这是一个很多方面的参数都可以通过.如果你不熟悉它们,我建议花一些时间来阅读维基百科的文章,尽管现在它主要是按值调用和按引用调用.
这意味着传递的内容将替换函数内的值名称.例如,使用此功能:
def f(x: => Int) = x * x
Run Code Online (Sandbox Code Playgroud)
如果我这样称呼它
var y = 0
f { y += 1; y }
Run Code Online (Sandbox Code Playgroud)
然后代码将像这样执行
{ y += 1; y } * { y += 1; y }
Run Code Online (Sandbox Code Playgroud)
虽然这提出了如果存在标识符名称冲突会发生什么的点.在传统的按名称调用中,会发生一种称为捕获避免替换的机制,以避免名称冲突.但是,在Scala中,这是以另一种方式实现的,结果相同 - 参数内的标识符名称不能引用被调用函数中的或标识符.
在解释其他两个问题之后,我还会谈到其他一些与名字相关的要点.
语法() => Type
代表a的类型Function0
.也就是说,一个不带参数并返回一些东西的函数.这相当于调用方法size()
- 它不需要参数并返回一个数字.
然而,有趣的是,这种语法与匿名函数文字的语法非常相似,这是造成一些混淆的原因.例如,
() => println("I'm an anonymous function")
Run Code Online (Sandbox Code Playgroud)
是arity 0的匿名函数文字,其类型为
() => Unit
Run Code Online (Sandbox Code Playgroud)
所以我们可以写:
val f: () => Unit = () => println("I'm an anonymous function")
Run Code Online (Sandbox Code Playgroud)
但是,重要的是不要将类型与值混淆.
这实际上只是一个Function1
,其第一个参数是类型Unit
.写它的其他方法是(Unit) => Type
或Function1[Unit, Type]
.事情是......这不太可能是人们想要的.该Unit
类型的主要目的是指示一个人不感兴趣的值,因此接收该值没有意义.
例如,考虑一下
def f(x: Unit) = ...
Run Code Online (Sandbox Code Playgroud)
有什么可以做的x
?它只能有一个值,因此无需接收它.一种可能的用途是链接函数返回Unit
:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
Run Code Online (Sandbox Code Playgroud)
因为andThen
只定义了Function1
,并且我们链接的函数正在返回Unit
,所以我们必须将它们定义为Function1[Unit, Unit]
能够链接它们的类型.
混淆的第一个原因是认为0-arity函数存在的类型和文字之间的相似性也存在于按名称调用.换句话说,想到,因为
() => { println("Hi!") }
Run Code Online (Sandbox Code Playgroud)
是文字为() => Unit
,然后
{ println("Hi!") }
Run Code Online (Sandbox Code Playgroud)
将是一个字面意思=> Unit
.它不是.这是一段代码,而不是文字.
混淆的另一个原因是写入了Unit
类型的值()
,它看起来像一个0-arity参数列表(但它不是).
Ben*_*son 36
case class Scheduled(time : Int, callback : => Unit)
Run Code Online (Sandbox Code Playgroud)
该case
修改使得隐含val
了每个参数的构造函数.因此(如有人指出)如果删除case
,可以使用call-by-name参数.无论如何编译器可能允许它,但如果它创建val callback
而不是变形,它可能会让人感到惊讶lazy val callback
.
当你改为callback: () => Unit
现在你的情况只需要一个函数而不是一个call-by-name参数.显然这个功能可以存储,val callback
所以没有问题.
获得所需内容的最简单方法(Scheduled(40, println("x") )
使用call-by-name参数传递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 })
}
Run Code Online (Sandbox Code Playgroud)
正在使用:
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190
scala> Scheduled(1234, println("x")).doit
x
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
23209 次 |
最近记录: |