Scala的“魔术”功能列表


72

我在哪里可以找到Scala的“神奇”的功能列表,如applyunapplyupdate+=,等?

魔术函数是指编译器的某些语法糖使用的函数,例如

o.update(x,y) <=> o(x) = y

我用Google搜索了的scala magic和的某种组合functions,但没有找到任何东西。

我对标准库中魔术函数的用法不感兴趣,但是其中存在魔术函数。

Answers:


79

我所知道的:

获得者/设定者相关:

apply
update
identifier_=

模式匹配:

unapply
unapplySeq

理解:

map
flatMap
filter
withFilter
foreach

前缀运算符:

unary_+
unary_-
unary_!
unary_~

除此之外,任何隐含的从A到B的Scala也将转换A <op>= BA = A <op> B,如果以前运营商没有定义,“OP”是不是字母数字,而<op>=不是!===<=>=

而且我不相信在任何地方都可以列出Scala的所有语法糖。


3
您可能要添加一元代码!等在其他职位之一中列出的运营商,因为这似乎是这里问题的最详尽解答:)
Calum

1
什么identifier_=啊 没看过。
Stefan Endrullis 2012年

@StefanEndrullis尝试:object X { var _x = 0; def x_=(n: Int) { _x = n }; def x = _x }; X.x = 5; println(X.x)
Daniel C. Sobral

@Daniel C. Sobral:好的,identifier这只是要成为一个占位符。得到它了。谢谢。
Stefan Endrullis 2012年

1
还有equals一个被称为==
Nikita,

17

除了update和之外apply,还有一些一元运算符(我认为)是神奇的:

  • unary_+
  • unary_-
  • unary_!
  • unary_~

再加上常规的infix /后缀运算符(几乎可以是任何东西),您便拥有了完整的软件包。

您确实应该看一下Scala语言规范。它是此资料的唯一权威来源。阅读起来并不难(只要您对上下文无关的语法感到满意),并且非常容易搜索。唯一不能很好指定的是XML支持。


12

抱歉,如果不能完全回答您的问题,但到目前为止,我最喜欢的WTF时刻是@作为模式匹配内的赋值运算符。多亏了“在Scala中编程”的软拷贝,我很快发现了它。

使用@我们可以将模式的任何部分绑定到变量,如果模式匹配成功,则变量将捕获子模式的值。这是Scala编程中的示例(第15.2节-变量绑定):

expr match {
  case UnOp("abs", e @ UnOp("abs", _)) => e
  case _ =>
}

如果整个模式匹配成功,则将与UnOp(“ abs”,_)部分匹配的部分用作变量e。

这里的什么编程斯卡拉说一下吧。

该链接不再起作用。是一个。


您能否与我们分享@运算符的作用?
Elazar Leibovich

4

我还要补充_*模式匹配上的任意数目参数的

case x: A(_*)

操作员关联规则,摘自Odersky-Spoon-Venners的书:

Scala中运算符的关联性由其最后一个字符决定。如<...>所述,任何以':'字符结尾的方法都将在其右操作数上调用,并传入左操作数。以其他任何字符结尾的方法都是相反的。它们在其左操作数上调用,并传入右操作数。因此a * b产生a。*(b),但是a :: b产生b.:::(a)。


也许我们还应该提到的语法脱糖的表现可以发现这里


还有(当然!)对的替代语法

a -> b //converted to (a, b), where a and b are instances

(如正确指出的那样,这只是通过库进行的隐式转换,因此它可能不符合条件,但我发现它是新手的常见难题)



1
IIRC->只是一个库函数。
Elazar Leibovich 2012年

4

我想补充一点,还有一个“魔术”特质- scala.Dynamic

启用动态调用的标记特征。x此特征的实例允许x.meth(args)对任意方法名称meth和参数列表进行方法调用,args以及x.field对任意字段名称进行字段访问field

如果呼叫本身不受支持x(即,如果类型检查失败),则会根据以下规则将其重写:

foo.method("blah")      ~~> foo.applyDynamic("method")("blah")
foo.method(x = "blah")  ~~> foo.applyDynamicNamed("method")(("x", "blah"))
foo.method(x = 1, 2)    ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2))
foo.field           ~~> foo.selectDynamic("field")
foo.varia = 10      ~~> foo.updateDynamic("varia")(10)
foo.arr(10) = 13    ~~> foo.selectDynamic("arr").update(10, 13)
foo.arr(10)         ~~> foo.applyDynamic("arr")(10)

从Scala 2.10开始,仅在启用语言功能动态的情况下,才可以定义此特征的直接或间接子类。

所以你可以做类似的事情

import scala.language.dynamics

object Dyn extends Dynamic {
  def applyDynamic(name: String)(a1: Int, a2: String) {
    println("Invoked " + name + " on (" + a1 + "," + a2 + ")");
  }
}

Dyn.foo(3, "x");
Dyn.bar(3, "y");

3

它们在Scala语言规范中定义。据我所知,您刚才提到的功能只有三个。

Scalas Getter和Setter也可能与您的“魔术”有关:

scala> class Magic {
 |     private var x :Int = _
 |     override def toString = "Magic(%d)".format(x)
 |     def member = x
 |     def member_=(m :Int){ x = m }
 | }

defined class Magic

scala> val m = new Magic

m: Magic = Magic(0)

scala> m.member

res14: Int = 0

scala> m.member = 100

scala> m

res15: Magic = Magic(100)

scala> m.member += 99

scala> m

res17: Magic = Magic(199)

如果您可以为我索取该主张的证据,那么您将回答我的问题;-)我以为它符合规范,但是在规范中查找它们并不是一件好事。
Elazar Leibovich,2009年

2
Scala语言规范:6.15赋值...如果x是在某些模板中定义的无参数函数,并且同一模板包含setter函数x_ =作为成员,则赋值x = e将解释为对x的调用x _ =(e)该设置器功能。类似地,将无参数函数x的赋值f .x = e解释为调用f .x _ =(e)。带有函数应用程序“ =”运算符左侧的赋值f(args)= e被解释为f .update(args,e),即调用由f定义的更新函数。
Eastsun

我指出,没有更多的证据了。
Elazar Leibovich
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.