Pytanie Jak sprawić, by wyliczenie było zgodne z protokołem w Swift?


Dokumentacja Swift mówi tak klasy, structs, i wylicza wszystkie mogą być zgodne z protokołami i mogę dojść do punktu, w którym wszyscy się zgadzają. Ale nie mogę dostać enum zachowywać się zupełnie jak klasa i struct przykłady:

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

Nie zorientowałem się, jak zdobyć simpleDescription zmienić się w wyniku połączenia adjust(). Mój przykład oczywiście tego nie zrobi, ponieważ rębacz ma wartość zakodowaną na stałe, ale jak ustawić wartość dla simpleDescription jednocześnie dostosowując się do ExampleProtocol?


76
2018-06-03 09:07


pochodzenie




Odpowiedzi:


Oto moja próba:

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

133
2018-06-04 08:35



Jest to zgodne z protokołem, ale nadal ma sens jako wyliczenie. Dobra robota! - David James
Niesamowite! Miałem pomysł stworzenia skorygowanego stanu, ale nie przyszło mi do głowy, że mógłbym się zmienić. Dopasuj metodę dopasowania. Dzięki! - Adrian Harris Crowne
Doskonały wskaźnik. Trochę utknęło na tym. Jedno pytanie jednak: Jakiś powód, dla którego dodałeś zwracaną wartość Voidu do funkcji dopasowania? - jpittman
@jpittman, ponieważ adjust funkcja zwraca Void w ExampleProtocol, to to samo, co po prostu używanie mutating func adjust(). Jeśli chcesz adjust aby mieć typ zwrotu, możesz zmienić protokół na: gist.github.com/anjerodesu/e1bf640576a3b6fa415f - Angelo
Nie można edytować odpowiedzi, aby poprawić błąd składni, brakuje kropki, powinno być case .Base: - John Doe


Oto moje podejście do tego.

Ponieważ to jest enum a nie a class, musisz myślę inaczej (TM): to twój opis musi się zmienić, gdy "stan" twojego enum zmiany (jak wskazał @ 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

Nadzieja, która pomaga.


40
2018-06-04 10:52



Zgadzam się z twoim podejściem do samego enum iz kodem, który podałeś. miły.
Ta odpowiedź jest ładniejsza i bardziej zwięzła niż przyjęta. - Ricardo Sanchez-Saez
Nawiasem mówiąc, możesz usunąć SimpleEnumeration.Adjusted i zastąpić po prostu ".Adjusted". Jeśli nazwa wyliczenia kiedykolwiek się zmienia, to o jeden mniej rzeczy do odświeżenia. - Shaolo
Tak, to jest lepsze. Dzięki. - Kruger Brent
Nie jest to jednak zgodne z podanym protokołem - barry


Oto inne podejście, wykorzystujące jedynie wiedzę zdobytą podczas wycieczki do tego momentu *

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

Jeśli chcesz adjust() działaj jako przełącznik (chociaż nie ma co sugerować, że tak jest), użyj:

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

* (Chociaż nie wspomina wyraźnie, jak określić typ zwracany i protokół)


11
2018-06-12 16:04



Myślę, że to podejście jest prawdopodobnie najlepszym rozwiązaniem. Szybka aktualizacja polega na tym, że prosty opis powinien zwrócić self.rawValue - Justin Levi Winter


Oto rozwiązanie, które nie zmienia aktualnej wartości wyliczenia, ale zamiast tego wartości ich instancji (na wszelki wypadek, jeśli jest to przydatne dla każdego).

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

7
2018-06-13 23:16



Dodatkowe punkty dla każdego, kto znajdzie sposób na uniknięcie tych wszystkich przełączników. Coś na wzór tej fikcyjnej kopii self = copy(self, self.desc + ", asdfasdf") - DiogoNeves


Nie można definiować zmiennych bez gettera i settera w wyliczeniach, a zatem niemożliwe jest posiadanie zmiennej, którą można modyfikować.

Możesz dostosować się do protokołu, ale nie możesz mieć takiego samego zachowania podczas mutowania, jak w klasach.


4
2018-06-03 11:07





To jest połączyć o enum w szybkim tempie.

Struktury i wyliczenia są typami wartości. Domyślnie właściwości typu wartości nie można modyfikować za pomocą metod instancji. połączyć

Następnie musisz użyć funkcji mutowania.

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

2
2018-06-13 03:48





Inną opcją jest adjust (), aby przerzucać pomiędzy przypadkami w następujący sposób:

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
2018-06-08 12:19





Oto budowanie na odpowiedzi Jacka:

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
2018-01-15 14:53





Wpadłem na to

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

1
2018-06-05 19:43





oto mój kod

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
2018-03-11 07:13