带存储字段的Swift枚举?

带存储字段的Swift枚举?,swift,enums,Swift,Enums,所以,我一直在寻找一个解决这个问题的方法大约有两天了。我翻阅了Swift文档,尝试了许多不同的google/stack overflow搜索,直接随机编写代码,但都没有用。我想问题的一部分是我不知道怎么用词。。。很抱歉,这让人困惑,但希望我附加的代码能澄清这一点 无论如何,我想知道是否有可能在一个枚举中有一个私有字段,这样每个枚举值都有它自己的值。我不是在问扩展另一个类,也不是在问相关的值。不幸的是,我还没有在网上看到任何关于Swift是否允许这样做的信息,以及如何做到这一点的信息。为了突出我的

所以,我一直在寻找一个解决这个问题的方法大约有两天了。我翻阅了Swift文档,尝试了许多不同的google/stack overflow搜索,直接随机编写代码,但都没有用。我想问题的一部分是我不知道怎么用词。。。很抱歉,这让人困惑,但希望我附加的代码能澄清这一点

无论如何,我想知道是否有可能在一个枚举中有一个私有字段,这样每个枚举值都有它自己的值。我不是在问扩展另一个类,也不是在问相关的值。不幸的是,我还没有在网上看到任何关于Swift是否允许这样做的信息,以及如何做到这一点的信息。为了突出我的问题,我正在尝试用Swift重新创建以下Java代码:

// Java

public enum Direction {

  LEFT(0, -1), RIGHT(0, 1), UP(-1, 0), DOWN(1, 0);

  private final int rowChange, colChange;

  Direction(int rowChange, int colChange) {
    this.rowChange = rowChange;
    this.colChange = colChange;
  }

  public int rowChange() {
    return this.rowChange;
  }

  public int colChange() {
    return this.colChange;
  }

}
这就是我目前所拥有的,它是有效的,但我更希望它有存储值,而不是通过每个可能的情况进行切换

// Swift

public enum Direction {

  case left, right, up, down

  public func rowChange() -> Int {
    switch self {
    case .left:
      return 0
    case .right:
      return 0
    case .up:
      return -1
    case .down:
      return 1
    }
  }

  public func colChange() -> Int {
    switch self {
    case .left:
      return -1
    case .right:
      return 1
    case .up:
      return 0
    case .down:
      return 0
    }
  }

}

打开
self
是标准方式。通过让枚举从Int继承(或字符串是另一种常见情况),可以将单个值分配给枚举。但对于这样的两个值,切换将是正常的方式

也许可以考虑使用结构体来代替?大概是这样的:

struct Direction: Equatable {

    let row: Int
    let column: Int

    static let left = Direction(row: 0, column: -1)
    static let right = Direction(row: 0, column: 1)
    static let up = Direction(row: -1, column: 0)
    static let down = Direction(row: 1, column: 0)

    private init() { 
        // Just to disable empty initialisation, not actually used.
        self.row = 0
        self.column = 0
    }

    private init(row: Int, column: Int) {
        self.row = row
        self.column = column
    }
}
let direction = Direction.left
let row = direction.row
let column = direction.column
public struct PointOffset {
    public var dX, dY: Int

    static func left (by distance: Int) { return self.init(dX: -distance, dY: 0) }
    static func right(by distance: Int) { return self.init(dX: +distance, dY: 0) }
    static func up   (by distance: Int) { return self.init(dX: 0, dY: +distance) }
    static func down (by distance: Int) { return self.init(dX: 0, dY: -distance) }
}
print(Direction.left.rawValue) // --> (0, -1)
print(Direction.left.rowChange) // --> 0
print(Direction.left.colChange) // --> -1
可以这样访问它:

struct Direction: Equatable {

    let row: Int
    let column: Int

    static let left = Direction(row: 0, column: -1)
    static let right = Direction(row: 0, column: 1)
    static let up = Direction(row: -1, column: 0)
    static let down = Direction(row: 1, column: 0)

    private init() { 
        // Just to disable empty initialisation, not actually used.
        self.row = 0
        self.column = 0
    }

    private init(row: Int, column: Int) {
        self.row = row
        self.column = column
    }
}
let direction = Direction.left
let row = direction.row
let column = direction.column
public struct PointOffset {
    public var dX, dY: Int

    static func left (by distance: Int) { return self.init(dX: -distance, dY: 0) }
    static func right(by distance: Int) { return self.init(dX: +distance, dY: 0) }
    static func up   (by distance: Int) { return self.init(dX: 0, dY: +distance) }
    static func down (by distance: Int) { return self.init(dX: 0, dY: -distance) }
}
print(Direction.left.rawValue) // --> (0, -1)
print(Direction.left.rowChange) // --> 0
print(Direction.left.colChange) // --> -1
此外,如果目标是使用模式匹配,那么当结构从
equalable
继承时,您可以编写如下内容:

switch direction {
case .left:
    break
case .right:
    break
case .up:
    break
case .down:
    break
default:
    break
}

打开
self
可以保证为枚举中的每个案例返回一个有效值,并且如果向枚举中添加新值,它将保护您,因为只有为新值添加案例,代码才会编译。不要使用func,请使用属性:

public enum Direction {

    case left, right, up, down

    var rowChange: Int {
        switch self {
        case .left: return 0
        case .right: return 0
        case .up: return -1
        case .down: return 1
        }
    }

    var colChange: Int {
        switch self {
        case .left: return -1
        case .right: return 1
        case .up: return 0
        case .down: return 0
        }
    }

}
调用它的示例:

let list: [Direction] = [.left, .right, .up, .down]
for e in list {
    print("ROW changed = \(e.rowChange)")
    print("COL changed = \(e.colChange)")
}

您的解决方案基本上是正确的,我将避免使用,并返回一个
(dX:Int,dY:Int)
元组,或者甚至类似于
点偏移量
结构。我还将使用computed属性,而不是无参数方法

public enum Direction {

    case left, right, up, down

    public var offset: (dX: Int, dY: Int) {
        switch self {
        case .left:  return (dX: -1,  dY:  0)
        case .right: return (dX: +1,  dY:  0)
        case .up:    return (dX:  0,  dY: +1)
        case .down:  return (dX:  0,  dY: -1)
        }
    }
}
如果您设想需要的方向不是单一的距离单位,那么我建议您从
enum
切换到
struct
,并执行以下操作:

struct Direction: Equatable {

    let row: Int
    let column: Int

    static let left = Direction(row: 0, column: -1)
    static let right = Direction(row: 0, column: 1)
    static let up = Direction(row: -1, column: 0)
    static let down = Direction(row: 1, column: 0)

    private init() { 
        // Just to disable empty initialisation, not actually used.
        self.row = 0
        self.column = 0
    }

    private init(row: Int, column: Int) {
        self.row = row
        self.column = column
    }
}
let direction = Direction.left
let row = direction.row
let column = direction.column
public struct PointOffset {
    public var dX, dY: Int

    static func left (by distance: Int) { return self.init(dX: -distance, dY: 0) }
    static func right(by distance: Int) { return self.init(dX: +distance, dY: 0) }
    static func up   (by distance: Int) { return self.init(dX: 0, dY: +distance) }
    static func down (by distance: Int) { return self.init(dX: 0, dY: -distance) }
}
print(Direction.left.rawValue) // --> (0, -1)
print(Direction.left.rowChange) // --> 0
print(Direction.left.colChange) // --> -1

您可以遵循
RawRepresentable
并使用
(Int,Int)
作为
Self.RawValue

enum Direction : RawRepresentable {
    case left, right, up, down

    var rawValue : (Int, Int) {
        switch self {
        case .left: return (0, -1)
        case .right: return (0, 1)
        case .up: return (-1, 0)
        case .down: return (1, 0)
        }
    }

    init?(rawValue: (Int, Int)) {
        switch rawValue {
        case (0, -1): self = .left
        case (0, 1): self = .right
        case (-1, 0): self = .up
        case (1, 0): self = .down
        case (_, _): return nil
        }
    }

    var rowChange : Int { return self.rawValue.0 }
    var colChange : Int { return self.rawValue.1 }
}
然后你可以这样使用它:

struct Direction: Equatable {

    let row: Int
    let column: Int

    static let left = Direction(row: 0, column: -1)
    static let right = Direction(row: 0, column: 1)
    static let up = Direction(row: -1, column: 0)
    static let down = Direction(row: 1, column: 0)

    private init() { 
        // Just to disable empty initialisation, not actually used.
        self.row = 0
        self.column = 0
    }

    private init(row: Int, column: Int) {
        self.row = row
        self.column = column
    }
}
let direction = Direction.left
let row = direction.row
let column = direction.column
public struct PointOffset {
    public var dX, dY: Int

    static func left (by distance: Int) { return self.init(dX: -distance, dY: 0) }
    static func right(by distance: Int) { return self.init(dX: +distance, dY: 0) }
    static func up   (by distance: Int) { return self.init(dX: 0, dY: +distance) }
    static func down (by distance: Int) { return self.init(dX: 0, dY: -distance) }
}
print(Direction.left.rawValue) // --> (0, -1)
print(Direction.left.rowChange) // --> 0
print(Direction.left.colChange) // --> -1

不相关的注意:应该使用
var列:Int{…}
而不是
func colChange()->Int{…}
。由于这是一个O(1)操作,事实上在Swift中编写它的方式是使用属性,而不是函数。可能重复感谢大家的反馈-我对Swift还是比较新的,所以我感谢大家的帮助。我将把它们转换为计算属性。。。Swift不允许我在Java中经常使用的东西,这有点奇怪,但我想开关也可以正常工作。
struct
方法的问题是,可以使用其他值创建其他方向。您至少应该将
init
设置为私有,以便只有4个静态项可见。并将这两个属性设置为只读的公共属性。@rmaddy关于private init的观点很好,但是列/行属性已经是只读的,所以我不确定您的意思。不管怎样,我只是提供OP一个switch语句的替代方案。更不用说这两个属性了。我一时忘记了它们是不可写的,因为它们是
let
.Hm,非常有趣-我甚至没有考虑过struct方法。谢谢你的意见!