对象方法调用没有括号

时间:2014-03-20 18:35:56

标签: scala dsl

导入后是否可以调用没有括号的对象方法?

这是我的测试代码,基于Martin Odersky的this article

package gardening.fruits

object PrintPlanted {
  def main(args: Array[String]) {
    // Call method on object
    import gardening.fruits
    fruits showFruit(apple)
    fruits showFruit apple

    // Import object
    import gardening.fruits._
    showFruit(apple)

    // showFruit apple

    // Error: missing arguments for method showFruit in package fruits;
    // follow this method with `_' if you want to treat it 
    // as a partially applied function
  }
}

导入包对象fruits后,我可以调用方法showFruit(apple),但有没有办法调用方法而没有括号,如最后一个代码?

我在一个小DSL中使用这样的方法,使用括号有点烦人。欢迎您提出所有建议。

2 个答案:

答案 0 :(得分:2)

不,这是不可能的。 e1 op e2是所谓的中缀操作,相当于e1.op(e2)。当接收器(e1)被遗漏时,这不起作用。出于同样的原因,你也不能写println "hello"之类的东西。

答案 1 :(得分:2)

好吧,Scala中几乎所有东西都可行:

package object fruits {
  val planted = List(apple, plum, banana)

  import scala.language.dynamics

  object showFruit extends Dynamic {

    private val lookupFruit = planted
        .map(f => (f.getClass.getSimpleName, f)).toMap;

    def applyDynamic(name: String)(args: Any*) = {
      realShowFruit(lookupFruit(name+"$"));
    }

    private def realShowFruit(fruit: Fruit) = {
      println(fruit.name + "s are " + fruit.color)
    }

  }
}

将使您的代码有效。

HOW?

我们正在用对象替换原始的showFruit方法。这个对象恰好是Dynamic,所以:

showFruit apple ~~> showFruit.applyDynamic("apple")([Some param, see below])

这意味着我们没有收到apple个对象,我们正在处理"apple"String)。

因此我们需要根据字符串名称查找水果。我正在使用地图和一些讨厌的Java反射:)。 apple对象实际上是gardening.fruits.apple$,因此我们的f.getClass.getSimpleName方法有效。

嗯,既然你知道如何做你想做的事,请不要。这实际上是一个真正破解的解决方法,模拟了post fix operator语法(by itself,不可取)。

这会给你带来各种各样的麻烦。假设你想使用这样的方法:

def main(args: Array[String]): Unit = {
    import com.sevenrtc.testreflection.fruits._
    showFruit apple // won't compile
}

但这会编译:

def main(args: Array[String]): Unit = {
    import com.sevenrtc.testreflection.fruits._
    showFruit apple 
    println("Will compile!");
}

为什么呢?出于同样的原因,这个编译:

def main(args: Array[String]): Unit = {
    import com.sevenrtc.testreflection.fruits._
    showFruit apple 
    ()
}

println())的结果实际上传递给applyDynamic。所以第一个例子相当于:

showFruit.apple(println("Will Compile!"))