Как сделать enum соответствовать протоколу в Swift?

В документации Swift говорится, что классы, структуры и перечисления могут соответствовать протоколам, и я могу добраться до точки, где все они соответствуют. Но я не могу заставить перечисление вести себя как примеры классов и структур:

protocol ExampleProtocol {
    var simpleDescription: String { get set }
    mutating func adjust()
}

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105

    func adjust() {
        simpleDescription += " Now 100% adjusted."
    }
}

var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"

    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}

var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

enum SimpleEnum: ExampleProtocol {
    case Base

    var simpleDescription: String {
        get {
            return "A Simple Enum"
        }
        set {
            newValue
        }
    }

    mutating func adjust() {
        self.simpleDescription += ", adjusted"
    }
}

var c = SimpleEnum.Base
c.adjust()
let cDescription = c.simpleDescription

Я не понял, как изменить simpleDescription в результате вызова adjust(). Мой пример, очевидно, не будет делать этого, потому что у получателя есть значение жестко закодированное, но как я могу установить значение для simpleDescription, все еще соответствующее ExampleProtocol?

Ответ 1

Это моя попытка:

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

enum ExampleEnum : ExampleProtocol {
    case Base, Adjusted

    var simpleDescription: String {
        return self.getDescription()
    }

    func getDescription() -> String {
        switch self {
        case .Base:
            return "A simple description of enum"
        case .Adjusted:
            return "Adjusted description of enum"
        }
    }

    mutating func adjust() {
        self = ExampleEnum.Adjusted
    }
}

var c = ExampleEnum.Base
c.adjust()
let cDescription = c.simpleDescription

Ответ 2

Вот мой пример.

Поскольку это enum, а не class, вам нужно думать о другом (TM): это описание, которое должно измениться, когда изменяется "состояние" вашего enum (как указано @ху-цян).

enum SimpleEnumeration: ExampleProtocol {
  case Basic, Adjusted

  var description: String {
    switch self {
    case .Basic:
      return "A simple Enumeration"
    case .Adjusted:
      return "A simple Enumeration [adjusted]"
    }
  }

  mutating func adjust()  {
    self = .Adjusted
  }
}

var c = SimpleEnumeration.Basic
c.description
c.adjust()
c.description

Надеюсь, что это поможет.

Ответ 3

Здесь другой подход, используя только знания, полученные от тура до этой точки *

enum SimpleEnumeration: String, ExampleProtocol {
    case Basic = "A simple enumeration", Adjusted = "A simple enumeration (adjusted)"

    var simpleDescription: String {
        get {
            return self.toRaw()
        }
    }

    mutating func adjust() {
        self = .Adjusted
    }
}

var c = SimpleEnumeration.Basic
c.adjust()
let cDescription = c.simpleDescription

Если вы хотите, чтобы adjust() выступал в качестве переключателя (хотя нет ничего, чтобы предположить, что это так), используйте:

mutating func adjust() {
    switch self {
    case .Basic:
        self = .Adjusted
    default:
        self = .Basic
    }
}

* (Хотя в нем явно не указано, как указать тип возврата и протокол)

Ответ 4

Здесь есть решение, которое не меняет текущее значение перечисления, но вместо этого его значения экземпляров (на всякий случай это полезно кому-либо).

enum ProtoEnumeration : ExampleProtocol {
    case One(String)
    case Two(String)

    var simpleDescription: String {
        get {
            switch self {
            case let .One(desc):
                return desc
            case let .Two(desc):
                return desc
            }
        }
    }
    mutating func adjust() {
        switch self {
        case let .One(desc):
            self = .One(desc + ", adjusted 1")
        case let .Two(desc):
            self = .Two(desc + ", adjusted 2")
        }
    }
}

var p = ProtoEnumeration.One("test")
p.simpleDescription
p.adjust()
p.simpleDescription

Ответ 5

Невозможно определить переменные без getter и setter в перечислениях, и поэтому невозможно изменить переменную, которую вы можете изменить.

Вы можете соответствовать протоколу, но вы не можете иметь такое же поведение с мутированием, как и в классах.

Ответ 6

Это ссылка о перечислении в swift.

Структуры и перечисления представляют собой типы значений. По умолчанию свойства типа значения не могут быть изменены из его методов экземпляра. ссылка

Затем вам нужно использовать функцию mutating.

enum ProtocolEnum: ExampleProtocol {
    case on, off
    var simpleDescription: String {
        switch self {
        case .on:
            return "Switch is ON"
        case .off:
            return "Switch is OFF"
        }
    }
    mutating func adjust() {
        switch self {
        case .on:
            self = off
        case .off:
            self = on
        }
    }
}

var c = ProtocolEnum.on
c.simpleDescription
c.adjust()
let cDescription = c.simpleDescription

Ответ 7

Другим вариантом является настройка() для переключения между случаями следующим образом:

enum SimpleEnum: ExampleProtocol {
    case Foo, Bar

    var simpleDescription: String {
    get {
        let value = self == .Foo
            ? "Foo"
            : "Bar"
        return "A simple \(value) enum."
    }
    }

    mutating func adjust() {
        self = self == .Foo
            ? .Bar
            : .Foo
    }
}

Ответ 8

Здесь здание на ответ Джека:

protocol ICanWalk {
    var description: String { get }
    mutating func stepIt()
}

enum TwoStepsForwardThreeStepsBack: Int, ICanWalk {
    case Base = 0, Step1, Step2

    var description: String {
        return "Step \(self.rawValue)"
    }

    mutating func stepIt() {
        if let nextStep = TwoStepsForwardThreeStepsBack( rawValue: self.rawValue + 1 ) {
            // going forward.
            self = nextStep
        } else {
            // back to the base.
            self = TwoStepsForwardThreeStepsBack.Base
        }
    }
}

Ответ 9

Я придумал этот

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

enum Seat: ExampleProtocol {
    case WindowSeat, MiddleSeat, AisleSeat

    var simpleDescription : String {
        switch self {
        case .WindowSeat:
            return "Window Seat"
        case .MiddleSeat:
            return "Middle Seat"
        case .AisleSeat:
            return "Aisle Seat"
        }
    }

    mutating func adjust() {
        switch self {
        case .WindowSeat:
            self = .MiddleSeat
        case .MiddleSeat:
            self = . AisleSeat
        case .AisleSeat:
            self = .WindowSeat
        }
    }
}

var seat = Seat.MiddleSeat
print(seat.simpleDescription) // Middle Seat
seat.adjust()
print(seat.simpleDescription) // Aisle Seat

Ответ 10

здесь мой код

enum SimpleEnum: ExampleProtocol {
    case Base, Adjusted
    var simpleDescription: String {
        get {
            var description = "A simple enum."
            switch self {
            case .Base:
                return description
            case .Adjusted:
                return description + " - [adjusted]"
            }
        }
    }
    mutating func adjust() {
        self = SimpleEnum.Adjusted
    }
}
var simpleEnum = SimpleEnum.Base
simpleEnum.adjust()
simpleEnum.simpleDescription

Ответ 11

Мой первый вклад здесь:

enum SimpleEnum: ExampleProtocol {
    case Basic(String), Adjusted(String)
    init() {
        self = SimpleEnum.Basic("A simple Enum")

    }

    var simpleDescription: String {
        get {
            switch self {
            case let .Basic(string):
                return string
            case let .Adjusted(string):
                return string
            }
        }
    }

    mutating func adjust() {
        self = SimpleEnum.Adjusted("full adjusted")

    }
}

var c = SimpleEnum()
c.adjust()
let cDescription = c.simpleDescription

Спасибо за других!

Ответ 12

Этот эксперимент тоже отбросил меня из-за предыдущих примеров SimpleClass и SimpleStructure, в которых свойство simpleDescription было внутренне изменено, что заставило меня думать, что мне нужно сделать то же самое. Просмотрев другие ответы, размещенные здесь, и прочитав официальную документацию Apple Swift 2.1, я придумал следующее:

protocol ExampleProtocol {
     var simpleDescription: String { get }
     mutating func adjust()
}

enum SimpleEnum: ExampleProtocol {
    case Simple
    case Adjusted

    var simpleDescription: String {
        switch self {
        case .Simple:
            return "A simple enumeration"
        case .Adjusted:
            return "A simple enumeration somewhat changed."
        }
    }

    mutating func adjust() {
        self = .Adjusted
    }

    mutating func restore() {
        self = .Simple
    }
}

var d: SimpleEnum = .Simple
d.simpleDescription

d.adjust()
d.simpleDescription

d.restore()
d.simpleDescription

Также обратите внимание, что в примерах, приведенных Apple для SimpleClass и SimpleStructure до этого эксперимента, простое описание теряется изнутри - вы не можете вернуть исходное значение (если, конечно, вы не сохраните его за пределами класса/структуры); это побудило меня создать метод restore() для примера SimpleEnum, который позволяет вам переключаться между значениями. Надеюсь, это кому-то полезно!

Ответ 13

Я думал, что целью является просто сохранить состояние и использовать описание, чтобы облегчить чтение текущего состояния:

enum SimpleEnum: ExampleProtocol {

    case Default, Adjusted

    init() {
        self = .Default
    }

    var simpleDescription: String { get { return "\(self) Value" }}

    mutating func adjust() {
        self = .Adjusted
    }
}

var simpleEnum = SimpleEnum()
simpleEnum.adjust()
let adjustedSimple = simpleEnum.simpleDescript

Ответ 14

Другой вариант: использование связанных значений для хранения и отображения предыдущей опции (в форме "Выбранный 1, скорректированный с 2, отрегулированный от 1, отрегулированный от 2, отрегулированный от 1" )

protocol ExampleProtocol {
     var simpleDescription: String { get }
     mutating func adjust()
}

indirect enum EnumWithDescription: ExampleProtocol {
    case option1(EnumWithDescription?)
    case option2(EnumWithDescription?)
    var simpleDescription: String {
        return "Selected " + getDescription()
    }
    internal func getDescription() -> String {
        var currentValue: String
        let previousValue : EnumWithDescription?
        switch self {
        case .option1(let previous):
            currentValue = "1"
            previousValue = previous
        case .option2(let previous):
            currentValue = "2"
            previousValue = previous
        }
        if let adjustedFrom = previousValue?.getDescription() {
            return "\(currentValue) adjusted from \(adjustedFrom)"
        }
        else {
            return "\(currentValue)"
        }
    }
    mutating func adjust() {
        switch self {
        case .option1:
            self = .option2(self)
        case .option2:
            self = .option1(self)
        }
    }
}
var d = EnumWithDescription.option1(nil)
d.simpleDescription
d.adjust()
d.adjust()
d.simpleDescription
// Output: "Selected 1, adjusted from 2, adjusted from 1, adjusted from 2, adjusted from 1"

Ответ 15

как насчет этого

enum SimpleEnum : ExampleProtocol {
    case Desc(String)
    init() {
        self = Desc("a simple enum")
    }
    var simpleDescription:String {
        get {
            return (Mirror(reflecting: self).children.first!.value as? String)!
        }
    }
    mutating func adjust() {
        self = SimpleEnum.Desc(self.desc + " adjusted")
    }
}
var e = SimpleEnum()
e.simpleDescription    # => "a simple enum"
e.adjust()
e.simpleDescription    # => "a simple enum adjusted"