我对Scala还是很陌生,这更多是出于好奇。
假设我有课
class Container()
{
def add(item: Item) ...
}
我可以这样调用它:container add item
。
我想知道如何将这种调用转换为英语般的add item to container
?可能会违反样式指南,但正如我说的那样,我很好奇。
答案 0 :(得分:4)
Andrey指出,由于方法和值的顺序,这是不可能的。但是您可以通过礼貌并添加“请”来解决此问题。
please add item to container
这是please
...的实现
object please {
case class Adder(item: Item) {
def to(c: Container) =
c.add(item)
}
def add(i: Item) = Adder(i)
}
如果您不喜欢please
,则其他选项包括siri
,alexa
,heyGoogle
和hal
:)
答案 1 :(得分:4)
因为我喜欢一个很好的挑战,所以我尝试了如果滥用了Scala提供的几乎所有危险和/或实验性功能,是否无法到达所需的位置,事实证明这是可能的:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.language.dynamics
import scala.language.postfixOps
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
case class Item(i: Int)
class Container { var item: Item = null; def add(i: Item) = item = i }
object to
object add extends Dynamic { def applyDynamic(item: String)(a: to.type) = new AddContainer}
class AddContainer extends Dynamic { def selectDynamic(container: String): Unit = macro addMacro }
/**
* Don't try this at home: not a foolproof macro!
*/
def addMacro(c: Context)(container: c.Tree): c.Tree = {
import c.universe._
val Literal(Constant(containerName: String)) = container
val q"$_.applyDynamic($item)($_)" = c.prefix.tree
val Literal(Constant(itemName: String)) = item
q"${TermName(containerName)}.add(${TermName(itemName)})"
}
// Exiting paste mode, now interpreting.
scala> object Test {
| val item = Item(1)
| val container = new Container
| println(container.item)
|
| add item to container
|
| println(container.item)
| }
defined object Test
scala> Test
null
Item(1)
让我们将其分解为可以理解的部分。
您要编写add item to container
,它被解析为add.item(to).container
。实现的后果是:
container
用作postfix运算符。item
和container
都在方法调用位置,但是我们希望它们引用当前作用域中的变量。为了克服这个问题,我们需要结合以下两个功能:
Dynamic
,我们可以将a.b(c)
变成a.applyDynamic("b")(c)
,将a.b
变成a.selectDynamic("b")
。这样,方法名称就变成了可以动态处理的字符串。String
文字,将它们变成TermName
,然后输出一个新的语法树,看起来像container.add(item)
。为简单起见,此宏仅适用于最普通的情况。要使其可靠地工作,可能需要花费更多的精力。并且要明确地说:这只是回答“需要什么”的问题。我怀疑是否有一个用例可以证明确实要这样做。但是,此处使用的技术可能会应用于某些非常高级但有效的用例。
答案 2 :(得分:2)
我觉得不可能。
这些类型的Scala DSL基本上只是方法调用链,没有点和括号:
v1.m1(v2).m2(v3)
写为
v1 m1 v2 m2 v3
,其中包含一些值v1, v2, ...
和方法m1, m2, ...
。
这里有
'add' value 'to' value
无论如何定义'add'
和'to'
,它都不适合value-method-value-method
模式。