1
213
一个很大的区别是
然后你可以做:
当希望持久化枚举(例如,对数据库)或从文件中的数据创建枚举时,这非常有用。但是,我发现一般情况下,枚举在scala中有点笨拙,并且有一种尴尬的附加组件的感觉,所以我现在倾向于使用
所以现在我的优势是…
AS @chaotic3quilibrium 指出(通过一些修正以便于阅读):
跟进其他答案,主要缺点是
|
2
63
更新: 一个新的 macro based solution 已经创建,远远优于下面我概述的解决方案。我强烈推荐使用这个新的 基于宏的解决方案 . And it appears plans for Dotty will make this style of enum solution part of the language. 哇喔!
总结:
我用两个类创建了一个解决方案;
Enumeration
和
EnumerationDecorated
,位于此
Gist
. 我没有将代码发布到这个线程中,因为枚举的文件非常大(+400行-包含许多解释实现上下文的注释)。
首先,让我们确保我们使用的是相同的枚举基本概念。让我们定义一个枚举,主要是根据
接下来,让我们看看发布的三种最常见的解决方案模式的简化版本:
枚举定义中的以下项不可用:
对于我当前的项目,我没有在Scala/Java混合项目路径周围承担风险的好处。即使我可以选择做一个混合项目,如果/当我添加/删除枚举成员,或者编写一些新的代码来处理现有的枚举成员时,第7项对于允许我捕获编译时问题至关重要。
枚举定义中的以下项不可用:
它是可以论证的,它确实符合枚举定义项5和6。对于5个人来说,声称它是有效的是一种延伸。对于6,保存额外的关联单例ness数据并不容易扩展。
枚举定义中的下列项目不可用(恰好与直接使用Java枚举的列表相同):
对于我当前的项目,如果/当我添加/删除枚举成员,或者编写一些新代码来处理现有的枚举成员时,第7项对于允许我捕获编译时问题至关重要。 因此,考虑到上述枚举定义,上述三种解决方案都不起作用,因为它们没有提供上述枚举定义中概述的所有内容:
这些解决方案中的每一个最终都可以被改写/扩展/重构,以试图覆盖每一个解决方案中缺少的一些需求。然而,Java
在这方面,我开始与
因为我的解决方案有两个特点;
枚举
和
枚举修饰
以及自从
下面是解决方案使用与上面相同的数据思想的结果(完全注释的版本
available here
)并在
这是我创建的一对新的枚举特性(位于 this Gist )实现枚举定义中所需和概述的所有功能。
表达的一个问题是枚举成员名必须重复(
考虑到这两个问题,我不得不放弃生成一个隐含的排序的尝试,并且必须显式地要求客户机用某种有序集概念定义和声明它。因为scala集合没有插入顺序集实现,所以我能做的最好的就是使用
考虑到设计需要第二个列表/集合排序
|
3
62
case对象已经返回了它们的toString方法的名称,因此不需要单独传递它。这里有一个类似于JHO的版本(为了简洁起见,省略了便利方法):
对象是懒惰的;通过使用VAL,我们可以删除列表,但必须重复该名称:
如果您不介意作弊,可以使用反射API或类似Google反射的东西预先加载枚举值。非Lazy Case对象为您提供最清晰的语法:
美观整洁,具有CASE类和Java枚举的所有优点。我个人定义对象外部的枚举值,以便更好地匹配惯用的scala代码:
|
4
26
与枚举相比,使用case类的优点是:
使用枚举而不是case类的优点是:
因此,一般来说,如果只需要按名称列出简单常量,请使用枚举。否则,如果您需要一些更复杂的东西或者需要编译器的额外安全性来告诉您是否指定了所有匹配项,那么就使用用例类。 |
5
15
更新:下面的代码有一个bug,描述如下
here
. 下面的测试程序可以工作,但是如果您要在DayOfWeek本身之前使用DayOfWeek.Mon(例如),它将失败,因为DayOfWeek尚未初始化(使用内部对象不会导致外部对象初始化)。如果您执行类似的操作,仍然可以使用此代码
如果你想要
那么,下面的内容可能是有意义的。欢迎反馈。 在这个实现中,有抽象枚举和枚举基类,您可以扩展它们。稍后我们将看到这些类,但首先,您将如何定义枚举:
请注意,您必须使用每个枚举值(调用其apply方法)使其生效。[我希望内部的物体不是懒惰的,除非我特别要求它们是懒惰的。我想。 当然,如果需要的话,我们可以将方法/数据添加到dayofweek、val或单个case对象中。 下面是使用这种枚举的方法:
以下是编译时得到的信息:
您可以将“day match”替换为“(day:@unchecked)match”,其中您不需要此类警告,或者在结尾只包含一个catch all case。 当您运行上述程序时,会得到以下输出:
注意,由于列表和映射是不可变的,您可以轻松地删除元素以创建子集,而不必破坏枚举本身。 以下是枚举类本身(以及其中的EnumVal):
下面是对它的更高级的使用,它控制ID,并向VAL抽象和枚举本身添加数据/方法:
|
6
11
我这里有一个很好的简单lib,它允许您使用密封的特性/类作为枚举值,而不必维护自己的值列表。它依赖于一个简单的宏,该宏不依赖于错误
|
7
10
更新日期:2017年3月
Anthony Accioly
, the
Dotty 但是(下一代scala编译器)将占据主导地位 dotty issue 1970 和 Martin Odersky's PR 1958 .
注:目前(2016年8月,6年后)有一项提议取消
|
8
8
当需要遍历或过滤所有实例时,case类与枚举的另一个缺点是。这是枚举的内置能力(以及Java枚举),而CASE类不自动支持这种能力。 换言之:“没有一种简单的方法可以获得具有case类的枚举值的总集合的列表”。 |
9
5
如果您认真维护与其他JVM语言(例如Java)的互操作性,那么最好的选择是编写Java枚举。这些工作透明地从斯卡拉和Java代码,这是可以说。
|
10
4
我已经看到了使case类模拟枚举的各种版本。这是我的版本:
它允许您构造如下所示的case类:
也许有人能想出一个更好的诀窍,而不是像我一样简单地将每个case类添加到列表中。这就是我当时能想到的全部。 |
11
2
最近几次我需要这两个选项时,我一直在反复讨论。直到最近,我还是倾向于使用密封特性/案例对象选项。 1)scala枚举声明
2)密封特性+案例对象
虽然这些都没有真正满足Java枚举给你的一切,下面是正反两方面: scala枚举 赞成的意见: -用于用选项实例化或直接假定准确的函数(从持久存储加载时更容易) -支持对所有可能值进行迭代 欺骗: -不支持非详尽搜索的编译警告(使模式匹配不理想) 外壳对象/密封特性 赞成的意见: -使用密封特性,我们可以预先实例化一些值,而其他值可以在创建时注入。 -完全支持模式匹配(定义了应用/不应用方法) 欺骗: -从持久存储进行实例化-您通常必须在这里使用模式匹配或定义自己的所有可能“枚举值”列表。 最终促使我改变观点的是以下几点:
这个
因此,我认为我今后的偏好是,在打算从存储库访问值时使用枚举,否则使用case对象/密封特性。 |
12
2
我更喜欢
我把代码贴在这里,希望它有用,也希望其他人可以改进它。
|
13
0
对于那些仍在寻找如何获得 GatesDa's answer to work : 您只需在声明case对象以实例化它之后引用它:
|
14
0
我认为拥有
相反,你会得到如下的东西:
|
Martee · 用抽象类型扩展trait的case类 6 年前 |
Georg Heiler · 将Typesafe配置解析为case类 6 年前 |
Avba · 用于从字符串创建case对象的scala“工厂”设计模式 6 年前 |
altayseyhan · Scala case类“显式公开状态” 7 年前 |
vicaba · 不成形。引用1个构造函数参数的所有case类 7 年前 |