如何使枚举符合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()。我的示例显然不会这样做,因为getter具有一个硬编码的值,但是如何simpleDescription在仍然符合ExampleProtocol?的同时设置一个值?

Answers:


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。谢谢!
Adrian Harris Crowne

优秀的指针。有点卡在这一个。但是有一个问题:您是否将Void的返回值添加到了adjust函数中?
jpittman 2014年

@jpittman,因为该adjust函数返回Void,与ExampleProtocol使用相同mutating func adjust()。如果您想要adjust返回类型,可以将协议更改为:gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo

1
无法编辑答案以更正语法错误,它缺少一个点,应为case .Base:
John Doe

44

这是我的看法。

由于这是一个enum而不是a class,因此您必须考虑different(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”。如果枚举的名称发生变化,那么重构就少了一件。
Shaolo 2014年

是的,这样更好。谢谢。
Arjun Kalidas

但是,这不符合给定的协议
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

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

另一种选择是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应该像其他人一样自我解释,但是不同的是我在枚举中使用init方法,并且具有默认的基本枚举。因此,当您在Swift操场上的结构和类示例中创建枚举对象时,您会看到。
Indra Rusmita 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"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.