Быстрые перечисления с сохраненными полями? - PullRequest
2 голосов
/ 03 июня 2019

Итак, я искал решение этой проблемы около 2 дней. Я перерыл документацию по Swift, перепробовал множество различных поисков переполнения в Google / Stack и просто набросал случайный код, но безрезультатно. Я думаю, что отчасти проблема в том, что я не знаю, как это выразить ... извините, это сбивает с толку, но, надеюсь, код, который я прикрепил, проясняет его.

В любом случае, я хочу знать, возможно ли иметь личное поле в перечислении, чтобы каждое значение перечисления имело свое значение для этого поля. Я не спрашиваю о расширении другого класса, и я не спрашиваю о связанных значениях. К сожалению, мне еще не приходилось сталкиваться с тем, что в Интернете говорится, разрешено ли это в Swift, и как это сделать. Чтобы подчеркнуть мой вопрос, я пытаюсь воссоздать следующий код Java в Swift:

// 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
    }
  }

}

Ответы [ 4 ]

2 голосов
/ 03 июня 2019

Вы можете соответствовать 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 }
}

Тогда вы можете использовать его так:

print(Direction.left.rawValue) // --> (0, -1)
print(Direction.left.rowChange) // --> 0
print(Direction.left.colChange) // --> -1
2 голосов
/ 03 июня 2019

Ваше решение в значительной степени правильная идея, я бы просто избежал примитивной одержимости и возвратил бы (dX: Int, dY: Int) кортеж, или, может быть, даже что-то вроде PointOffset структуры.Я бы также использовал вычисляемое свойство вместо метода без параметров.

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, и делать что-то вроде этого:

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) }
}
2 голосов
/ 03 июня 2019

Включение self является стандартным способом. Вы можете иметь одно значение, назначенное для перечисления, позволяя ему наследовать от Int (или String - другой распространенный случай). Но для двух таких значений переключение будет нормальным.

Может быть, рассмотреть возможность использования структуры вместо? Как то так:

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

Кроме того, если целью является использование сопоставления с образцом, это возможно, когда структура наследуется от Equatable, что позволяет написать что-то вроде:

switch direction {
case .left:
    break
case .right:
    break
case .up:
    break
case .down:
    break
default:
    break
}
1 голос
/ 03 июня 2019

Использование параметра self гарантирует, что вы возвращаете действительное значение для каждого регистра в вашем перечислении, и защитит вас, если вы когда-нибудь добавите новое значение в перечисление, потому что тогда ваш код не будет компилироваться, пока выдобавить случай для нового значения.Не используйте функцию, используйте свойство:

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)")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...