Bagaimana cara membuat enum sesuai dengan protokol di Swift?

93

Dokumentasi Swift mengatakan bahwa class , struct , dan enum semuanya dapat menyesuaikan dengan protokol, dan saya dapat mencapai titik di mana semuanya sesuai. Tapi saya tidak bisa mendapatkan enum untuk berperilaku seperti contoh class dan struct :

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

Saya belum menemukan cara untuk mendapatkan simpleDescriptionperubahan sebagai hasil dari panggilan adjust(). Contoh saya jelas tidak akan melakukannya karena pengambil memiliki nilai hard-code, tetapi bagaimana saya dapat menetapkan nilai untuk simpleDescriptionsementara masih sesuai dengan ExampleProtocol?

Adrian Harris Crowne
sumber

Jawaban:

155

Ini adalah usaha saya:

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
Hu Qiang
sumber
Ini memenuhi protokol tetapi masih masuk akal sebagai enum. Kerja bagus!
David James
1
Hebat! Saya memiliki gagasan untuk membuat keadaan yang disesuaikan, tetapi tidak terpikir oleh saya bahwa saya dapat mengubah ke. Diatur dalam metode penyesuaian. Terima kasih!
Adrian Harris Crowne
Pointer yang bagus. Agak terjebak yang satu ini. Namun satu pertanyaan: Ada alasan Anda menambahkan nilai kembali Void ke fungsi penyesuaian?
jpittman
@jpittman karena adjustfungsinya kembali Voiddalam ExampleProtocol, itu sama dengan hanya menggunakan mutating func adjust(). Jika Anda ingin adjustmemiliki tipe pengembalian, Anda dapat mengubah protokol ke: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo
1
Tidak dapat mengedit jawaban untuk mengoreksi kesalahan sintaks, tidak ada titik, seharusnyacase .Base:
John Doe
44

Ini pendapat saya.

Karena ini adalah enumdan bukan a class, Anda harus berpikir berbeda (TM) : deskripsi Anda yang harus berubah ketika "keadaan" Anda enumberubah (seperti yang ditunjukkan oleh @ 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

Semoga membantu.

Zedenem
sumber
saya setuju dengan pendapat Anda tentang enum itu sendiri, dan dengan kode yang Anda berikan. bagus.
4
Jawaban ini lebih bagus dan lebih ringkas daripada jawaban yang diterima.
Ricardo Sanchez-Saez
2
Sekadar catatan bahwa Anda dapat menghapus SimpleEnumeration.Adjusted dan mengganti dengan hanya ".Adjusted". Jika nama pencacahan pernah berubah maka satu hal yang perlu dilakukan adalah refactor.
Shaolo
Ya, ini lebih baik. Terima kasih.
Arjun Kalidas
Ini tidak sesuai dengan protokol yang diberikan
barry
11

Berikut pendekatan lain, hanya menggunakan pengetahuan yang diperoleh dari tur hingga saat itu *

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

Jika Anda ingin adjust()bertindak sebagai toggle (meskipun tidak ada yang menyarankan hal ini), gunakan:

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

* (Meskipun tidak secara eksplisit menyebutkan cara menentukan tipe kembalian dan protokol)

Jack James
sumber
2
Saya pikir pendekatan ini mungkin yang terbaik dari kelompok itu. Pembaruan cepat adalah bahwa simpleDescription harus mengembalikan self.rawValue
Justin Levi Winter
7

Berikut adalah solusi yang tidak mengubah nilai enum saat ini, tetapi nilai instance-nya (untuk berjaga-jaga jika itu berguna bagi siapa saja).

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
DiogoNeves
sumber
Poin ekstra untuk siapa pun yang menemukan cara untuk menghindari semua pengalihan tersebut. Sesuatu di sepanjang garis salinan fiktif iniself = copy(self, self.desc + ", asdfasdf")
DiogoNeves
4

Tidak mungkin untuk mendefinisikan variabel tanpa getter dan setter dalam enum dan oleh karena itu tidak mungkin memiliki variabel yang dapat Anda modifikasi.

Anda dapat mengikuti protokol tetapi Anda tidak dapat memiliki perilaku yang sama dengan mutasi seperti di kelas.

Tomáš Linhart
sumber
2

Ini adalah tautan tentang enum dengan cepat.

Struktur dan enumerasi adalah tipe nilai. Secara default, properti dari tipe nilai tidak dapat diubah dari dalam metode instance-nya. tautan

Kemudian, Anda harus menggunakan fungsi mutasi.

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
Jeff Gu Kang
sumber
1

Opsi lainnya adalah untuk menyesuaikan () untuk beralih antar kasus sebagai berikut:

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
    }
}
Endersstocker
sumber
1

Inilah membangun jawaban Jack:

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
        }
    }
}
Alex Akhtyrskiy
sumber
1

Saya datang dengan ini

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
Groot
sumber
0

inilah kode saya

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
CAM
sumber
0

Kontribusi pertama saya di sini:

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

Terima kasih untuk yang lainnya!

Indra Rusmita
sumber
1
Bisakah Anda juga menambahkan penjelasan?
Robert
@Robert itu harus dijelaskan sendiri seperti yang lain tetapi perbedaannya adalah saya menggunakan metode init dalam enum dan memiliki enum dasar default. jadi Anda akan melihat itu ketika Anda membuat objek enum seperti dalam struktur dan contoh kelas di taman bermain Swift.
Indra Rusmita
0

Eksperimen ini membuat saya bingung juga, karena contoh SimpleClass dan SimpleStructure sebelumnya yang menunjukkan properti simpleDescription sedang dimodifikasi secara internal, yang membuat saya berpikir bahwa saya perlu melakukan hal yang sama. Setelah melihat jawaban lain yang diposting di sini dan membaca dokumentasi resmi Apple Swift 2.1, saya mendapatkan ini:

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

Perhatikan juga bahwa dalam contoh yang diberikan oleh Apple untuk SimpleClass dan SimpleStructure sebelum percobaan ini, deskripsi sederhana hilang secara internal - Anda tidak bisa mendapatkan kembali nilai aslinya (kecuali tentu saja Anda menyimpannya di luar kelas / struktur); inilah yang mendorong saya untuk membuat metode restore () untuk contoh SimpleEnum, yang memungkinkan Anda untuk beralih antara nilai-nilai. Semoga ini bermanfaat bagi seseorang!

William L. Marr III
sumber
0

Saya berpikir bahwa tujuannya hanyalah untuk mempertahankan status dan menggunakan deskripsi untuk membuat status saat ini lebih mudah dibaca:

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
Johan
sumber
0

Variasi lain: Menggunakan nilai terkait untuk menahan dan menampilkan opsi sebelumnya (dari bentuk "Dipilih 1, disesuaikan dari 2, disesuaikan dari 1, disesuaikan dari 2, disesuaikan dari 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"
nkalvi.dll
sumber
-1

bagaimana dengan ini

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"
michex
sumber