枚举和Clojure

22
在Java/C世界中,人们经常使用枚举。如果我在使用一个使用枚举的Java库,我可以通过一些反射技巧将它们与关键字相互转换,例如使用(. java.lang.Enum valueOf e..., (aget ^"[Ljava.lang.Enum;" (. e (getEnumConstants)) i)等方法。但在Clojure世界中,人们是否需要像枚举(命名整数)这样的东西?如果不需要,那么他们的代码结构是如何实现的,以便不需要枚举?如果需要,那么有什么相应的替代方案吗?我感觉我真正想问的是索引(用于循环),这在函数式编程中很少用到(目前我只使用过map-indexed方法一次)。
3个回答

20

我所看到的大部分Clojure代码中,关键字通常用于代替枚举。它们是带有命名空间的关键字,并具有关键字的所有其他有用属性,同时编写起来更加容易。它们并不是一种完全的替代,因为它们比Java枚举更具动态性(例如动态类型)。

至于索引和循环,我发现更符合惯用语法的方法是在一个关键字序列上进行映射:

(map do-stuff [:a :b :c :d] (range)) 

与其循环枚举值,我还没有在Clojure代码中找到此类示例,尽管此类示例很可能存在 ;-)


20

正如 Arthur指出 - 在Clojure中通常使用关键字(keywords)代替枚举。

你不会经常看到数字索引的使用-它们在Clojure(或大多数其他函数式编程语言)中不是特别习惯用法。

还有一些值得注意的选项:

  • 如果需要使用数字值,可以直接使用Java枚举 - 例如:java.util.concurrent.TimeUnit/SECONDS
  • 如果您希望定义自己的常量,请使用vars - 例如:(def ^:const PURPLE 1)
  • 甚至可以使用宏defenum实现更高级的枚举功能和简单的语法。

枚举系统的一个潜在好处是确保运行时不允许非成员值。在Clojure中有什么好的方式来满足这一点? - Drew Noakes
Clojure的方式对我来说更多地涉及使用验证工具/测试等方面。例如,可以查看Prismatic的Schema库-https://github.com/prismatic/schema - mikera
谢谢,我会去看看。clj-schema 似乎也是另一个选择。 - Drew Noakes
在Clojure的验证工具中,你现在可以列举(眨眼!)Clojure Spec - luskwater
1
如果您正在使用关键字,(s/def :dog/breed #{:labrador :huskador :husky}) 是检查“它必须是这些值之一”的传统方式。任何其他值都可以放入集合中,无论是Java枚举、整数还是字符串。 - luskwater
显示剩余2条评论

7

是的,在大多数Java程序员使用枚举的地方,可以使用关键字。在极少数需要每个编号的情况下,您可以简单地定义一个转换映射:{:dog 0,:rabbit 1,...}

另一方面,我编写的第一个Clojure库就是这样一个 defenum 宏,它为符号分配了数字并创建了前后转换系统。这是一个合理实现但非常糟糕的想法,因此请随意查看 ,但我不建议您使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接