当选择合适时和申请时,我很困惑。我认为apply是一个函数或方法应用程序,因此
scala> val expr = u reify { Random.nextInt }
expr: reflect.runtime.universe.Expr[Int] = Expr[Int](Random.nextInt())
scala> u showRaw expr.tree
res0: String = Apply(Select(Ident(scala.util.Random), newTermName("nextInt")), List())
是我的期望;带有空参数列表的nextInt应用程序。
此外,
scala> val expr = u reify { Random.shuffle(List("sammy", "snake")) }
expr: reflect.runtime.universe.Expr[List[String]] = Expr[List[String]](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom))
scala> u showRaw expr.tree
res2: String = Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom"))))
再次是我所期望的 - 一个shuffle方法的应用,带有一个字符串列表。
然而,
scala> val expr = u reify { Random.shuffle(List("sammy", "snake")).head }
expr: reflect.runtime.universe.Expr[String] = Expr[String](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom).head)
scala> u showRaw expr.tree
res1: String = Select(Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom")))), newTermName("head"))
是头上的选择。我很困惑,因为我会认为那个外部节点将是头部的应用程序。当head是一种方法时,为什么选择它?
是否有一个网页详细说明了选择和应用之间的区别,因为我找不到。
答案 0 :(得分:4)
Select
和Apply
的含义纯粹是语法上的。
Select(prefix, newTermName("member"))
表示prefix.member
Apply(prefix, List(arg1, arg2, ...))
表示prefix(arg1, arg2, ...)
技术上,Random.nextInt
是Select
,但Scala类型检查器将其包含在另外的Apply
中,因为Random.nextInt
被定义为一个带有单个空参数的函数名单。换句话说,这是一个由类型搜索者执行的贬低。
List
的{{1}}方法不是这种情况。如果你看一下它的定义,它需要 no 参数列表:
head
这就是为什么类型检查器不会将它包装在def head: A
树中。
总结 - 采用单个空参数列表的方法与不采用参数列表的方法之间存在差异。作为一个语法糖,Scala允许使用单个空参数列表调用方法,就好像它们没有参数列表(没有任何parens),但是在这种情况下,类型检查器仍会添加Apply
。
答案 1 :(得分:1)
在这种情况下,树精确地再现了Scala程序的语法结构。 Select
对应于成员选择,例如到foo.bar
,而Apply
代表参数列表的应用,例如baz(1, 2, 3)
。
如果我们在Scala中有一个空的arglist方法,例如def x() = ???
(或Random.nextInt()
),然后可以将其调用写为Select
(对应something.x
)和Apply(Select(...), Nil)
(对应{{1} }),因为两者都是有效的Scala表达式。
如果我们在Scala中使用了一个nullary方法,例如something.x()
(或def y = ???
),则其调用只能写为List.head
(对应Select
)。如果我们写somethingElse.y
,那就意味着Apply(Select(...), Nil)
,这意味着将空参数列表应用于somethingElse.y()
上调用方法y
的结果。