【问题标题】:How to make an enum conform to a protocol in Swift?如何使枚举符合 Swift 中的协议?
【发布时间】:2014-07-23 13:16:15
【问题描述】:

Swift 文档说 classesstructsenums 都可以符合协议,我可以达到它们都符合的程度符合。但我无法让 enum 的行为与 classstruct 示例非常相似:

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

我还没有弄清楚如何通过调用adjust() 来更改simpleDescription。我的示例显然不会这样做,因为 getter 具有硬编码的值,但是如何在仍然符合 ExampleProtocol 的同时为 simpleDescription 设置值?

【问题讨论】:

    标签: swift enums swift-protocols


    【解决方案1】:

    这是我的尝试:

    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
    

    【讨论】:

    • 太棒了!我有创建调整状态的想法,但我没有想到我可以在调整方法中更改为 .Adjusted 。谢谢!
    • 优秀的指针。有点卡在这个上。不过有一个问题:您有什么理由将 Void 的返回值添加到调整函数中?
    • @jpittman 因为adjust 函数在ExampleProtocol 中返回Void,这与只使用mutating func adjust() 相同。如果希望adjust 有返回类型,可以将协议更改为:gist.github.com/anjerodesu/e1bf640576a3b6fa415f
    • 无法编辑答案以纠正语法错误,它缺少一个点,应该是case .Base:
    【解决方案2】:

    这是我的看法。

    由于这是enum 而不是class,您必须思考不同(TM):当您的@987654323 的“状态”出现时,您的描述必须改变@更改(正如@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
    

    希望对您有所帮助。

    【讨论】:

    • 我同意您对枚举本身的看法以及您提供的代码。不错。
    • 这个答案比公认的更好,更简洁。
    • 请注意,您可以删除 SimpleEnumeration.Adjusted 并仅替换为“.Adjusted”。如果枚举的名称发生变化,那么重构就少了一件事情。
    • 是的,这样更好。谢谢。
    • 虽然这不符合给定的协议
    【解决方案3】:

    这是另一种方法,仅使用从游览中获得的知识*

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

    *(虽然没有明确提到如何指定返回类型协议)

    【讨论】:

    • 我认为这种方法可能是其中最好的一种。快速更新是 simpleDescription 应该返回 self.rawValue
    【解决方案4】:

    这是一个不改变当前枚举值,而是改变它们的实例值的解决方案(以防万一它对任何人有用)。

    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")
    【解决方案5】:

    在枚举中定义没有getter和setter的变量是不可能的,因此不可能有一个可以修改的变量。

    您可以遵守协议,但不能像在类中那样具有与变异相同的行为。

    【讨论】:

      【解决方案6】:

      这是一个link关于swift中的枚举。

      结构和枚举是值类型。默认情况下,值类型的属性不能从其实例方法中修改。 link

      然后,您必须使用变异功能。

      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
      

      【讨论】:

        【解决方案7】:

        另一种选择是让 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
            }
        }
        

        【讨论】:

          【解决方案8】:

          这是基于 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
                  }
              }
          }
          

          【讨论】:

            【解决方案9】:

            我想出了这个

            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
            

            【讨论】:

              【解决方案10】:

              另一种变体:使用关联值来保存和显示上一个选项 (形式为“选择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"
              

              【讨论】:

                【解决方案11】:

                这是我的代码

                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
                

                【讨论】:

                  【解决方案12】:

                  我在这里的第一个贡献:

                  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
                  

                  感谢其他人!

                  【讨论】:

                  • 你能不能再补充一个解释?
                  • @Robert 它应该像其他人一样自我解释,但不同的是我在枚举中使用 init 方法并且具有默认的基本枚举。因此,当您在 Swift 游乐场中的结构和类示例中创建枚举对象时,您会看到这一点。
                  【解决方案13】:

                  这个实验也让我失望了,因为之前的 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() 方法的原因,它允许您在值之间来回切换它。希望这对某人有用!

                  【讨论】:

                    【解决方案14】:

                    我认为目标只是保留状态并使用描述使当前状态更易于阅读:

                    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
                    

                    【讨论】:

                      【解决方案15】:

                      这个怎么样

                      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"
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-12-22
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-12-16
                        相关资源
                        最近更新 更多