Как получить следующий случай перечисления (т.е. написать циркуляционный метод) в Swift 4.2 - PullRequest
0 голосов
/ 29 июня 2018

Swift 4.2 представляет новый протокол CaseIterable, который автоматически генерирует свойство массива всех дел в перечислении.
Теперь я хочу реализовать метод по умолчанию для наследования Enum от CaseIterable, который может возвращать следующий случай конкретного случая. Если этот случай - последний случай, верните первый случай. Как круг.
Если я напишу это для конкретного Enum, он будет работать правильно:

enum Direction: CaseIterable {
  case east, south, west, north

  func next() -> Direction {
    let all = type(of: self).allCases // 1
    if self == all.last! {
      return all.first!
    } else {
      let index = all.firstIndex(of: self)!
      return all[index + 1]
    }
  }
}

print(Direction.east.next()) // south  
print(Direction.north.next()) // east  

Но я хочу реализовать эту функцию для многих Enum. Повторное копирование и вставка кода не годятся (не говоря уже о том, что этот код абсолютно одинаков для каждого Enum).
Я попробовал это. Но что-то пошло не так.
(Я предлагаю вам скопировать следующий код на игровую площадку, чтобы вы могли быстрее понять эту проблему):

extension CaseIterable {
  func next() -> Self {
    let all = type(of: self).allCases // 1
    if self == all.last { // 2
      return all.first!
    } else {
      let index = all.firstIndex { (ele) -> Bool in
        self == ele // 3
      }
      return all[index + 1]
    }
  }
}

Три очка:

  1. all - Self.AllCases, тип Collection. Но в приведенном выше методе это [Direction].
  2. Ошибка в строке 2 говорит Value of type 'Self.AllCases' has no member 'last' (Даже если я не использую last, ошибки в строке 3 нельзя избежать.)
  3. В строке 3 ошибка Binary operator '==' cannot be applied to two 'Self' operands

И даже я использую общие ограничения, это то же самое.

func next<T: CaseIterable>(element: T) -> T {...}

Есть какие-нибудь решения? :)

Ответы [ 2 ]

0 голосов
/ 12 марта 2019

Если кто-то заинтересован в делах previous и next, вот обновление предыдущего ответа:

extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
    func previous() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let previous = all.index(before: idx)
        return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
    }

    func next() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return all[next == all.endIndex ? all.startIndex : next]
    }
}
0 голосов
/ 29 июня 2018

Некоторые проблемы с вашим подходом:

  • Протокол Collection не определяет свойство last.
  • Чтобы сравнить элементы с ==, они должны быть Equatable.
  • Индексы коллекции не обязательно являются целыми числами, их нужно увеличивать с index(after:).

Похоже, это рабочее решение (протестировано с Xcode 10.0 beta 2):

extension CaseIterable where Self: Equatable {
    func next() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return all[next == all.endIndex ? all.startIndex : next]
    }
}

Пример:

enum Direction: CaseIterable {
    case east, south, west, north
}

print(Direction.east.next()) // south
print(Direction.north.next()) // east

Примечания:

  • Только перечисления без связанных значений CaseIterable, и это также Equatable (но компилятор не понимает, что само собой). Поэтому Self: Equatable не является реальное ограничение.
  • Self.allCases можно использовать в Swift 4.2 для доступа к свойству типа из метода экземпляра.
  • Принудительное развертывание безопасно, потому что мы знаем , что значение элемент allCases.
  • Ваш enum Direction: CaseIterable компилируется, потому что бетон enum Direction тип - Equatable, а Direction.allCases - Array - с целочисленными индексами и свойством last.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...