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

Mic*_*ael 6 smalltalk pharo

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

Pet*_*nak 5

琐碎的方法

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

因此,您可以将示例编写如下:

Direction class>>input
    ^ #input

Direction class>>output
    ^ #output
Run Code Online (Sandbox Code Playgroud)

以及用法:

Direction input
Run Code Online (Sandbox Code Playgroud)

主要缺点是:

  • 即使枚举不同,任何其他碰巧返回相同值的“枚举”都将等于此值(您可以返回eg ^ self name + '::input'
  • 在调试过程中,您会看到该对象的实际值,这对于基于数字的枚举尤为丑陋(呃……这7是什么意思?

对象方法

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

该对象应:

  • 覆盖=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 << ')'
Run Code Online (Sandbox Code Playgroud)

用法还是一样

Direction input.
DirectionEnum output asString. "'a DirectionEnum(output)'"
Run Code Online (Sandbox Code Playgroud)

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

显然,这需要做更多的工作,但是效果更好。如果您有许多枚举,则可以将基本行为移至新的超类Enum,然后DirectionEnum只需要包含类端方法即可。


Lea*_*lia 5

最接近枚举类型的 Smalltalk 特性是SharedPool(aka PoolDictionary)。因此,如果您要将某个枚举从 Java 移植到 Smalltalk,您可能需要使用SharedPool. 这样做的方法如下:

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

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

例如,您可以使用类变量等定义SharedPool命名的子ColorConstants'Red', 'Green', 'Blue', 'Black', 'White',如下所示:

SharedPool
  subclass: #ColorConstants
  instanceVariableNames: ''
  classVariableNames: 'Red Green Blue Black White'
  poolDictionaries: ''
  package: 'MyPackage'
Run Code Online (Sandbox Code Playgroud)

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

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..."
Run Code Online (Sandbox Code Playgroud)

评估后,ColorConstants initialize您将能够在课堂上使用游泳池

Object
  subclass: #MyClass
  instanceVariableNames: 'blah'
  classVariableNames: ''
  poolDictionaries: 'ColorConstants'
  package: 'MyPackage'
Run Code Online (Sandbox Code Playgroud)

MyClass(及其子类)中,您可以按名称引用颜色:

MyClass >> displayError: aString
   self display: aString foreground: Red background: White

MyClass >> displayOk: aString
   self display: aString foreground: Green background: Black
Run Code Online (Sandbox Code Playgroud)