列挙型をSwiftのプロトコルに準拠させる方法は?


93

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()ゲッターにはハードコードされた値があるため、私の例では明らかにそれを行いませんがsimpleDescriptionExampleProtocol?に準拠しながら、どうやってwhileの値を設定できますか?

回答:


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
驚くばかり!調整済みの状態を作成するというアイデアはありましたが、adjustメソッドで.Adjustedに変更できるとは思いもしませんでした。ありがとう!
エイドリアンハリスクラウン2014年

優れたポインタ。これには少しこだわっていました。ただし、1つの質問:Voidの戻り値を調整関数に追加した理由は何ですか?
jpittman 2014年

@jpittmanはadjust関数がVoidで返されるため、ExampleProtocol単にを使用するのと同じmutating func adjust()です。あなたがしたい場合はadjust、戻り値の型を持っている、あなたはにプロトコルを変更することができます。gist.github.com/anjerodesu/e1bf640576a3b6fa415f
アンジェロ

1
答えを編集して構文エラーを修正できませんでした。ドットが欠落しているはずですcase .Base:
John Doe

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

お役に立てば幸いです。


enum自体に対するあなたの見解と、あなたが提供したコードに同意します。いいね。

4
この回答は、承認された回答よりも簡潔で簡潔です。
Ricardo Sanchez-Saez 2014年

2
SimpleEnumeration.Adjustedを削除して、単に ".Adjusted"に置き換えることができるということを補足しておきます。列挙型の名前が変わる場合は、リファクタリングする必要が1つ少なくなります。
Shaolo

ええ、これは良いです。ありがとう。
Arjun Kalidas 2017

ただし、これは指定されたプロトコルに準拠していません
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
このアプローチはおそらく最も優れたアプローチの1つだと思います。簡単な更新は、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

列挙型でゲッターとセッターなしで変数を定義することは不可能であるため、変更可能な変数を持つことは不可能です。

プロトコルに準拠することはできますが、クラスを変更する場合と同じように動作させることはできません。


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

別のオプションは、次のようにadjust()がケースを切り替えることです。

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

@Robertそれは他の人のように自己説明されるはずですが、違いは私が列挙型でinitメソッドを使用しており、デフォルトの基本列挙型を持っていることです。そのため、Swiftプレイグラウンドで構造体やクラスの例のように列挙型オブジェクトを作成すると、
インドラルスミタ2015年

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に対して示した例では、簡単な説明が内部的に失われていることに注意してください。元の値を戻すことはできません(もちろん、クラス/構造の外に保存しない限り)。これが、私がSimpleEnumサンプルのrestore()メソッドを作成するきっかけとなりました。このメソッドを使用すると、値を切り替えることができます。これが誰かに役立つことを願っています!


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"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.