【发布时间】:2012-02-07 22:55:38
【问题描述】:
使用 Clojure,我如何创建以下对象?该对象取自java代码(From Effective Java):
NutritionFacts cocaCola =
new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();
【问题讨论】:
标签: clojure
使用 Clojure,我如何创建以下对象?该对象取自java代码(From Effective Java):
NutritionFacts cocaCola =
new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();
【问题讨论】:
标签: clojure
虽然很难与其他答案中的简洁性争论1,但.. 已经有些失宠,取而代之的是更通用的->。我个人更喜欢:
(-> (NutritionFacts$Builder. 240 8)
(.calories 100)
(.sodium 350)
(.carbohydrates 27)
(.build))
多了几个字符,但你得到了两件事:
. 就在那里。最重要的是,这个问题的所有其他答案都把类名弄错了:Java 的 NutritionFacts.Builder 是名为 NutritionFacts$Builder 的真正 JVM 类的语言糖,而该类是 Clojure 必须引用的类(因为我们不是使用 javac 编译我们的代码)。
1 我不同意doto 的建议:它之所以有效,只是因为这个 Builder 类碰巧通过改变单个实例然后返回它来实现其方法链。 doto 非常适合需要就地突变的 Java 对象,但是当一个类足以假装它是不可变的时,您真的应该使用方法链接版本(即,->)。
【讨论】:
(:import [com.blah.blah NutritionFacts$Builder])
使用.. 宏。这是两个连续的点。它可以满足您的需要 - 在前一个的结果上连续调用下一个 Java 方法。
我没有 REPL,但你的行应该翻译成这样的:
(.. (NutritionFacts.Builder. 240 8)
(calories 100)
(sodium 350)
(carbohydrates 27)
(build))
【讨论】:
我只是从 Clojure 开始,但对我来说它看起来像是标准方法调用:
(doto
(NutritionFacts.Builder. 240 8)
(.carbohydrates 27)
(.sodium 35)
(.calories 100)
(.build)
)
编辑:
正如@Goran Jovic 指出的那样,这会调用以第一种形式创建的对象的所有方法。
所以它在这种情况下有效,因为 Java 代码使用方法链,但不是更普遍适用。
【讨论】:
doto 和.. 之间的主要区别在于doto 调用第一种形式定义的对象上的方法,而.. 对前一个形式的结果进行每次调用。在这种情况下,它是相同的,因为 Java 方法不断返回正在构建的对象。
(.. (NutrionalFacts.Builder. 240 8) (calories 100) (sodium 35) (carbohydrates 27) (build))
【讨论】:
这个线程已有几年历史了,据我所知,线程优先宏仍然是首选方式,但不需要 $ 语法。 斜线 (/) 也可以:
(-> (Caffeine/newBuilder)
(.maximumSize 10000)
(.build))
【讨论】:
(Caffeine/newBuilder) 是对静态方法的调用 (Java Caffeine.newBuilder()) 而(NutritionalFacts$Builder.) 是对静态类的构造函数的调用 (Java new NutritionalFacts.Builder()),所以这真的不是t 与接受的答案有任何不同。