【问题标题】:Java (or Groovy) equivalent of Scala's applyJava(或 Groovy)等效于 Scala 的 apply
【发布时间】:2014-09-18 19:13:22
【问题描述】:

在 Scala 中,如果有一个对象 Foo 具有 apply(x: Int),我可以用 Foo(42) 调用它(作为 Foo.apply(42) 的简写)。

是否可以在 Java 或 Groovy 中复制它?我原以为 Groovy 的 call 功能可能类似,但 def call(int x)static def call(int x) 都没有导致调用 call

编辑:根据要求添加示例 DSL

典型/现有 DSL:alter 't' add 'a' storing BAR(其中BAR 是一个枚举)。 尝试在上面添加一些代替 BAR 的内容,但会接受一个参数,但语法不会有太多差异 ,理想情况下:alter 't' add 'a' storing FOO(42)

我已经将 FOO 创建为一个具有接受 int 的构造函数的类 - 我现在正在寻找一种通过 FOO(42) 而不是 new FOO(42)FOO.call(42) 调用该构造函数的方法

【问题讨论】:

  • 很酷的问题你能提供更多信息吗
  • @KickButtowski 它适用于通常调用枚举但需要添加带有参数的内容的 DSL - 因此它被实现为类而不是枚举。但理想情况下,我希望这种特殊情况的 DSL 语法尽可能接近其他情况。 FOO(42)new FOO(42)FOO.call(42) 更接近 FOO
  • @Exupery 你能发布一些你的 DSL 的例子吗?可能有一些解决方法
  • 一般来说 DSL 是一个不错的主意,但在搞砸了一些之后,我绝对讨厌将某些语言混为一谈以制作一种既不能识别为原始语言也不能识别为“自然语言”的混合语言的想法”。如果您要编写 DSL,为什么不直接自己解析呢?这样你就可以得到你正在寻找的确切语言和.not_some random english_like.text.with bizarre_syntax_requireme.nts??
  • @WillP 添加示例 DSL

标签: java groovy


【解决方案1】:

Groovy 中最直接的方法是在类上编写static call() 方法,但它不会使Clazz() 工作。这可能是一个错误,但我找不到关于它的 JIRA。

我想建议使用闭包:

import groovy.transform.Canonical as C

@C class Bar { def bar }

@C class Baz { def baz }

A = { new Bar(bar: it) }

B = { new Baz(baz: it) }


assert A("wot") == new Bar(bar: "wot")
assert B("fuzz") == new Baz(baz: "fuzz")

更新:似乎类名在被调用者上下文中解析为静态方法调用,这是可行的(但在 DSL 中不可用):

class A { 
    static call(str) { str.toUpperCase() } 
}
assert ((Class)A)("qwop") == "QWOP"

更新 2:根据您的 DSL 示例,删除括号是否可行?

class FOO {}


def params = [:]

alter = { 
  params.alter = it
  [add : { 
      params.add = it
      [storing: { 
          params.clazz = it
          [:].withDefault { params.param = it }
      }]
  }]
}


alter 't' add 'a' storing FOO 42


assert params == [
  alter : 't',
  add   : 'a',
  clazz : FOO,
  param : '42'
]

【讨论】:

  • 使用@Canonical 是无可挑剔的。 :)
  • 删除括号绝对没问题-但是您的示例重写了所有 DSL,这绝对不是。我需要一个完全独立于其他任何东西来处理FOO 42 部分的解决方案。
  • @Exupery 是第一个例子,使用闭包,合适吗?
  • 是的,带闭包的那个是合适的!很抱歉昨天没有注意到 - 我觉得我没有一个好地方可以粘贴相当于 A = { new Bar(bar: it) } 但再次查看它我意识到我可以将它放在枚举上的静态方法中(保持所有其他/正常"FOOs") 并将方法命名为 FOO。然后我当然意识到我可以用那种方法坚持return new FOO(x),哈。感谢您让我走上正确的道路! [你的回答肯定解决了我的问题的通用/原始形式]
  • call() 也适用于枚举,如果有任何帮助的话:enum P { E; def call() { "wot" } }; assert P.E() == "wot"
【解决方案2】:

Groovy 中的Closure 有方法call() 可以省略:

def action = { a, b = 1 -> println "$a and $b" }
action.call 1 // prints "1 and 1"
action( 1, 3 ) // prints "1 and 3"

在 Java 中,最接近的替代方法是 Runnable:它提供无参数 run(),但不能短手

【讨论】:

  • 也适用于课程class Foo { def call(x) { println x } }; foo = new Foo(); foo(42)
  • @cfrick 评论应该是一个答案。
  • @cfrick 它可以与静态call 一起使用吗?只是想知道这里是否可以使用完全相同的 scala 语法。
  • @cfrick 这更接近我正在寻找的东西,但在不实例化 Foo 的情况下需要它
  • @Opal 似乎无法通过简单地添加 static 来工作。乍一看,call.metaClass.Foo 也不起作用。
猜你喜欢
  • 2022-01-08
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
相关资源
最近更新 更多