我可以将枚举定义为另一个枚举案例的子集吗?

Mis*_*cha 8 enums subset restriction swift

注意:这与我昨天在Stackoverflow上发布的另一个问题基本相同.但是,我认为我在那个问题中使用了一个不好的例子,这个例子并没有完全归结为我的想法.由于对原始帖子的所有回复都提到了第一个问题,我认为将新示例放在一个单独的问题中可能更好一点 - 没有重复的意图.


可以移动的模型游戏角色

让我们定义一个简单游戏中使用的方向枚举:

enum Direction {
    case up
    case down
    case left
    case right
}
Run Code Online (Sandbox Code Playgroud)

现在在游戏中我需要两种角色:

  • HorizontalMover只能左右移动的A.
  • A VerticalMover只能上下移动.

他们都可以移动所以他们都实现了

protocol Movable {
    func move(direction: Direction)
}
Run Code Online (Sandbox Code Playgroud)

那么让我们定义两个结构:

struct HorizontalMover: Movable {
    func move(direction: Direction)
    let allowedDirections: [Direction] = [.left, .right]
}

struct VerticalMover: Movable {
    func move(direction: Direction)
    let allowedDirections: [Direction] = [.up, .down]
}
Run Code Online (Sandbox Code Playgroud)

问题

...使用这种方法是我仍然可以将不允许的值传递move()函数,例如以下调用将是有效的:

let horizontalMover = HorizontalMover()
horizontalMover.move(up) // ??
Run Code Online (Sandbox Code Playgroud)

当然,我可以在move()函数内部检查是否direction允许传递此Mover类型,否则抛出错误.但是由于我确实有编译时允许的情况,我还希望在编译时进行检查.

所以我真正想要的是:

struct HorizontalMover: Movable {
    func move(direction: HorizontalDirection)
}

struct VerticalMover: Movable {
    func move(direction: VerticalDirection)
}
Run Code Online (Sandbox Code Playgroud)

where HorizontalDirectionVerticalDirection是枚举的子集Direction枚举.

像这样独立定义两个方向类型没有多大意义,没有任何共同的"祖先":

enum HorizontalDirection {
    case left
    case right
}

enum VerticalDirection {
    case up
    case down
}
Run Code Online (Sandbox Code Playgroud)

因为那时我不得不一遍又一遍地重新定义相同的情况,对于代表方向的每个枚举,它们在语义上是相同的.例如,如果我添加另一个可以向任何方向移动的角色,我也必须实现一般方向枚举(如上所示).然后我会leftHorizontalDirection枚举中有一个案例和left一般Direction枚举中的一个案例,它们彼此不了解这不仅是丑陋的,而且在分配和利用我必须重新分配的原始值时成为一个真正的问题每个枚举.


那么有没有办法解决这个问题呢?

我可以将枚举定义为另一个枚举的子集吗?

enum HorizontalDirection: Direction {
    allowedCases:
        .left
        .right
}
Run Code Online (Sandbox Code Playgroud)

nag*_*rrr 3

不可以。目前 Swift 枚举无法实现这一点。

我能想到的解决方案:

  • 使用我在您的其他问题中概述的协议
  • 回退到运行时检查