2015-02-07 68 views
1

我尝试将以下特征混合到我的类中,以享受类似Boolean类型的行为。如何使用闭集的值创建您自己的类型,在Scala

trait ReadyStates { // well, this is really used like an enumeration 
    class ReadyState 
    object Ready extends ReadyState 
    object NotReady extends ReadyState 
} 

但是,这不起作用,因为这个特征混入的每个类都创建它自己的对象。所以当在不同类的成员之间传递返回值时,Ready不可能天真地与Ready比较。

我怎样才能得到一个自定义类型,它有自己的一组允许值,与布尔值相同truefalse,它们可以跨类进行无缝比较?

我看了一下枚举,他们当时看起来并不很亮。

谢谢!

+3

似乎'ReadyStates'应该只是一个'object',其他类只是使用它的子类型?另外考虑让'ReadyState'密封和抽象。 – 2015-02-07 21:17:09

+0

这意味着'ReadyStates.Ready'需要使用的地方。不太像“真”和“假”。但是,它的工作原理! – matanster 2015-02-07 21:23:25

+1

如果你输入了blah.package.name.ReadyStates._' – 2015-02-07 21:24:33

回答

5

用@米-Z的评论的鼓舞下,我最终使用:

sealed abstract class ReadyState 
object Ready extends ReadyState 
object NotReady extends ReadyState 

没有任何包装对象。简单。

+1

,那么不行。这就是代数和类型在Scala中的编码方式。作为例子,请看'Boolean','List'等。事实上,这几乎是“密封”存在的唯一原因。 – 2015-02-07 22:19:20

+2

我写了一个关于Scala中正确的面向对象的布尔类型的小实现,在Programmers.SE的回答中看起来像是这样,如果你感兴趣的话:http://programmers.stackexchange.com/a/266635/1352 – 2015-02-07 22:23:15

+0

@JörgWMittag ..不确定Scala是如何实现布尔值的,那么..它的值是否只是扩展它的类型,或者类似于代码中的类型?他们感觉像某种类型的文字而不是类型,按照'true.getClass'的REPL。现在只是好奇。 – matanster 2015-02-08 14:07:50

3

为了进一步扩展马特的回答,我通常会做:

sealed trait ReadyState 
object ReadyState { 
    case object Ready extends ReadyState 
    case object NotReady extends ReadyState 
} 

包装纸的情况下的陪伴对象的对象ReadyState避免命名空间污染。比如现在你可以有另一种ADT,像

sealed trait AnotherState 
object AnotherState { 
    case object Ready extends AnotherState 
    case object NotReady extends AnotherState 
} 

ReadyNotReady名称将不会发生冲突,因为他们是“命名空间”的各个物体下。

此外,使用case objects(或类)允许编译器检查详尽的匹配。