clojure java
来自Java背景,我目前正在尝试借助在线资源和指导来学习Clojure编程语言。 几周前,我试图通过寻找与Java流中可用方法等效的方法来将各事物结合在一起。
虽然我设法使事情正常进行,但是编写工作代码和编写惯用代码是两个非常不同的事情。 我很幸运地获得了来自不同来源的大量反馈: Hacker News , Reddit和这个博客 。 我要感谢所有以积极方式做出贡献的人,这些人给了我关于Clojure的更多见解。 这篇文章是我收到的最常见反馈的总结。
这是在学习Clojure的焦点series.Other职位包括7 个职位:
- 解码Clojure代码,让您不知所措
- 学习Clojure:应对动态打字
- 学习Clojure:arrow和doto宏
- 学习Clojure:动态调度
- 学习Clojure:依赖类型和基于合同的编程
- 学习Clojure:与Java流进行比较
- 关于学习Clojure的反馈:与Java流进行比较 (本文)
- 学习Clojure:换能器
惯用关键字图
让我们从关于字典访问的简单但似乎非常普遍的用法开始。
为了通过字典中的键检索值,我最初使用了一个命名函数。 然后,我继续使用匿名函数:
(map #(:name %) justice-league)
实际上,匿名函数在Clojure中是样板的。 可以将其替换为简单的关键字访问:
(map :name justice-league)
这将返回相同的结果,但是语法更短。
过滤出零值
为了滤除nil
值,我用(not)
可用的(nil?)
检查取反了:
(filter #(not (nil? %)) [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil])
产生:
({:vehicles [:sandbox.function/Bat-Mobile :sandbox.function/Bat-Plane]}
{:vehicles [:sandbox.function/Invisible-Plane]})
但是Clojure提供了一个开箱即用的功能,它的功能完全相同,名为(some?)
。 它的定义如下:
如果x不为nil,则返回true,否则返回false。
用(some?)
替换初始函数组合非常简单:
(filter some? [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil])
总之,最好直接调用一个函数-如果有一个可用的函数,而不是反转另一个函数。
保持在一起
当仅需要保留来自单个键的字典值时,将产生下一个改进。 在上一篇文章中,我依次使用(filter)
和(map)
:
(->> [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil]
(filter some?)
(map :vehicles))
输出如下:
([:sandbox.function/Bat-Mobile :sandbox.function/Bat-Plane]
[:sandbox.function/Invisible-Plane])
Clojure提供了一个开箱即用的函数,称为(keep)
,其行为类似:
返回(f项目)的非零结果的惰性序列。
https://clojuredocs.org/clojure.core/keep
本质上, (keep)
仅将映射函数f
应用于非nil
值。 因此,使用它更新上面的代码很容易:
(keep :vehicles [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil])
赢取Mapcat!
最后,我们需要展平结果集合。 这是我以前使用的代码:
(->> [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil]
(keep :vehicles)
(flatten))
返回:
(:sandbox.function/Bat-Mobile
:sandbox.function/Bat-Plane
:sandbox.function/Invisible-Plane)
有趣的是,以下内容等同于上述片段:
(->> [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil]
(keep :vehicles)
(apply concat))
返回一个懒惰的seq,表示所提供coll中元素的串联。
https://clojuredocs.org/clojure.core/concat
可替代地,Clojure的提供(mapcat)
函数,映射函数和应用的组合(concat)
返回将concat应用于将map应用于f和colls的结果。 因此,函数f应该返回一个集合。
https://clojuredocs.org/clojure.core/mapcat
因此,上面的代码可以利用它,如下所示:
(mapcat :vehicles [nil
{:vehicles [::Bat-Mobile, ::Bat-Plane]}
{:vehicles [::Invisible-Plane]}
nil
nil
nil])
由于应用(concat),nil值会自动过滤掉
最后结果
总而言之,“原始代码”:
(->> justice-league
(map #(:vehicles %))
(filter #(not (nil? %)))
(flatten))
可以用以下简单的单线替换:
(mapcat :vehicles justice-league)
结论
在我以前的文章中,我写道Clojure语法非常有限。 一些评论者不同意这种措词。 实际上,我只能确认:基本构建块很少。
另一方面,有很多可用的现成的宏和函数。 了解它们可以使冗长难读的代码与惯用的代码有所不同。
再次感谢所有给我反馈的人。 我希望继续学习Clojure,如有需要,请不要犹豫,引导我正确的方向!
clojure java