在Smalltalk中定义枚举类型的惯用方法是什么?

时间:2018-03-23 13:37:33

标签: smalltalk pharo

就像Java,C#等。我如何在Smalltalk中定义类似enum Direction { input, output }的内容?

4 个答案:

答案 0 :(得分:4)

琐碎的方法

最简单的方法是让类方法返回符号或其他基本对象(如整数)。

所以你可以按如下方式编写你的例子:

Direction class>>input
    ^ #input

Direction class>>output
    ^ #output

用法:

Direction input

主要缺点是:

  • 任何其他" enum"即使枚举不同(您可以返回,例如^ self name + '::input'
  • ,恰好返回相同值的值将等于此值
  • 在调试过程中,你会看到对象的实际值,对于基于数字的枚举来说尤其难看(呃......这是什么意思?

对象方法

更好的方法是创建自己的枚举对象并返回它的实例。

这样的对象应该:

  • 覆盖=hash,因此您可以按值对它们进行比较,并使用枚举作为哈希集合中的键(字典)
  • 存储实际的唯一值表示
  • 使用自定义printOn:方法来简化调试

它可能看起来像这样

Object subclass: #DirectionEnum
    slots: { #value }
    classVariables: {  }
    category: 'DirectionEnum'

"enum accessors"
DirectionEnum class>>input
    ^ self new value: #input

DirectionEnum class>>output
    ^ self new value: #output

"getter/setters"
DirectionEnum>>value
    ^ value

DirectionEnum>>value: aValue
    value := aValue

"comparing"
DirectionEnum>>= anEnum
    ^ self class = anEnum class and: [ self value = anEnum value ]

DirectionEnum>>hash
    ^ self class hash bitXor: self value hash

"printing"
DirectionEnum>>printOn: aStream
    super printOn: aStream.
    aStream << '(' << self value asString << ')'

用法仍然相同

Direction input.
DirectionEnum output asString. "'a DirectionEnum(output)'"

解决了琐碎方法中提到的问题。

显然这是更多的工作,但结果更好。如果你有很多枚举,那么将基本行为移动到新的超类Enum是有意义的,然后DirectionEnum只需要包含类方法。

答案 1 :(得分:3)

与枚举类型最接近的Smalltalk功能是SharedPool(a.k.a。PoolDictionary)。因此,如果您将某些枚举从Java转移到Smalltalk,则可能需要使用SharedPool。以下是如何操作:

对于您类型中的每个枚举,您将在池中定义一个关联,其中key为类型名称,value为类型值。

在某些方言中PoolDictionaries是字典,在Pharo中它们是SharedPool的子类。因此,在Pharo中,您将所有类型名称声明为类变量。然后在初始化方法(类侧)中将值与键关联。

例如,您可以使用类变量SharedPool等定义名为ColorConstants的{​​{1}}的子类,如下所示:

'Red', 'Green', 'Blue', 'Black', 'White'

要将名称与值相关联,请在以下行添加类侧初始化方法:

SharedPool
  subclass: #ColorConstants
  instanceVariableNames: ''
  classVariableNames: 'Red Green Blue Black White'
  poolDictionaries: ''
  package: 'MyPackage'

评估ColorConstants class >> initialize Red := Color r: 1 g: 0 b: 0. Green := Color r: 0 g: 1 b: 0. Blue := Color r: 0 g: 0 b: 1. Black := Color r: 0 g: 0 b: 0. White := Color r: 1 g: 1 b: 1. "and so on..." 后,您就可以在班级中使用该池

ColorConstants initialize

Object subclass: #MyClass instanceVariableNames: 'blah' classVariableNames: '' poolDictionaries: 'ColorConstants' package: 'MyPackage' (及其子类)中,您可以按名称引用颜色:

MyClass

答案 2 :(得分:2)

由于Smalltalk是动态类型的,因此无论如何都不能将变量的值限制为对象的子集,因此枚举成员和全局常量之间没有区别,除了通过枚举名称的命名空间。

编辑:有关如何定义枚举常量的选项,请参阅Peter的答案。请允许我提一下,如果满足您的需求,您也可以直接使用符号。 direction := #input. direction := #output

答案 3 :(得分:2)

对于简单的情况,只需使用彼得建议的符号 - 您也可以将可能的值存储在IdentityDictionary中。

如果你的意思是Java中可用的更强大的枚举(它们可能不仅仅是一种命名常量;它们可以有行为,复杂的属性等),那么我就拿它比Peter更进一步,只为每个枚举类型创建一个子类。即使您正在谈论大量的枚​​举(您的用例似乎只需要两个),也不要害怕拥有许多子类,其中只有一个或两个方法用于区分他们彼此相处,大部分工作都是在共同的超类中完成的。