Як змусити перерахування відповідати протоколу в Swift?


93

Документація Swift говорить про те, що класи , структури та перерахунки можуть відповідати протоколам, і я можу дістатись до точки, коли вони всі відповідають. Але я не можу змусити enum поводитися так, як приклади класу та структури :

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(). Мій приклад, очевидно, не зробить цього, тому що в getter є жорстке кодування значення, але як я можу встановити значення, simpleDescriptionпоки все ще відповідає ExampleProtocol?

Відповіді:


155

Це моя спроба:

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

Це задовольняє протокол, але все одно має сенс як перерахування. Гарна робота!
Девід Джеймс,

1
Дивовижно! У мене була така ідея створення скоригованого стану, але мені не прийшло в голову, що я можу перейти на. Налаштований у методі коригування. Дякую!
Адріан Гарріс Кроун,

Відмінна покажчик. Трохи застряг на цьому. Хоча одне питання: з якої причини ви додали до функції регулювання повернене значення Void?
jpittman

@jpittman, оскільки adjustфункція повертається Voidв ExampleProtocol, це те саме, що просто використовувати mutating func adjust(). Якщо ви хочете adjustмати тип повернення, ви можете змінити протокол на: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo

1
Не вдалося відредагувати відповідь, щоб виправити синтаксичну помилку, у ній відсутня крапка, має бутиcase .Base:
Джон Доу

44

Ось мій погляд на це.

Оскільки це не, enumа не class, ви повинні думати інакше (TM) : саме ваш опис повинен змінитися, коли "стан" ваших enumзмін (на що вказував @ hu-qiang).

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

Сподіваюся, що це допомагає.


Я погоджуюся з вашим сприйняттям самої перерахунку та з наданим вами кодом. приємно.

4
Ця відповідь є приємнішою та коротшою, ніж прийнята.
Рікардо Санчес-Саез,

2
Тільки примітка, що ви можете видалити SimpleEnumeration.Adjusted та замінити просто ".Adjusted". Якщо ім'я переліку коли-небудь змінюється, то це рефакторинг на менше.
Шаоло

Так, це вже краще. Дякую.
Арджун Калідас,

Це не відповідає даному протоколу
barry

11

Ось інший підхід, використовуючи лише знання, отримані під час екскурсії до цього моменту *

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

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


2
Я думаю, що цей підхід, мабуть, найкращий з цих груп. Швидке оновлення полягає в тому, що simpleDescription має повернути self.rawValue
Justin Levi Winter

7

Ось рішення, яке не змінює поточне значення перерахунку, а замість них їх екземпляри (про всяк випадок, коли це корисно комусь).

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

Додаткові бали для того, хто знайде спосіб уникнути всіх цих перемикачів. Щось по лінії цієї вигаданої копіїself = copy(self, self.desc + ", asdfasdf")
DiogoNeves

4

Неможливо визначити змінні без getter і setter в переліченнях, а тому неможливо мати змінну, яку ви можете змінити.

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


2

Це посилання про енму в швидкому.

Структури та перерахування - цінні типи. За замовчуванням властивості типу значення не можуть бути змінені в межах його методів екземпляра. посилання

Тоді вам доведеться використовувати функцію мутації.

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

1

Інший варіант полягає в налаштуваннях () для перемикання між справами наступним чином:

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

1

Ось на основі відповіді Джека:

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

1

Я це придумав

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

0

ось мій код

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

0

Мій перший внесок тут:

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

Дякую за інших!


1
Чи можете ви також додати пояснення?
Роберт

@Robert слід пояснити себе, як і інші, але різними є те, що я використовую метод init in enum та маю базовий enum за замовчуванням. тож ви побачите, що ви створюєте об’єкт enum, наприклад, за структурою та прикладом класу на майданчику Swift.
Індра Русміта

0

Цей експеримент також відкинув мене через попередні приклади 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 до цього експерименту, простий опис втрачається внутрішньо - ви не можете повернути початкове значення (якщо, звичайно, ви не збережете його поза класом / структурою); саме це підштовхнуло мене до створення методу Resto () для прикладу SimpleEnum, який дозволяє перемикати його вперед і назад між значеннями. Сподіваюся, це комусь корисно!


0

Я думав, що мета просто зберегти стан і використовувати опис, щоб спростити читання поточного стану:

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

0

Інший варіант: Використання пов'язаних значень для утримання та відображення попереднього параметра (форми "Вибрано 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"

-1

як щодо цього

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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.