จะทำให้ enum สอดคล้องกับโปรโตคอลใน Swift ได้อย่างไร


97

เอกสารสวิฟท์กล่าวว่าการเรียน , structsและenumsทุกคนสามารถเป็นไปตามโปรโตคอลและฉันจะได้รับไปยังจุดที่พวกเขาทั้งหมดสอดคล้อง แต่ฉันไม่สามารถได้รับenumจะประพฤติค่อนข้างชอบชั้นและ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

ฉันไม่ได้คิดวิธีการที่จะได้รับการเปลี่ยนแปลงเป็นผลมาจากการโทรsimpleDescription adjust()ตัวอย่างของฉันเห็นได้ชัดว่าจะไม่ทำเช่นนั้นเนื่องจากgetterมีค่าฮาร์ดโค้ด แต่ฉันจะตั้งค่าในsimpleDescriptionขณะที่ยังคงเป็นไปตามค่าได้ExampleProtocolอย่างไร

คำตอบ:


158

นี่คือความพยายามของฉัน:

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

สิ่งนี้เป็นไปตามโปรโตคอล แต่ก็ยังสมเหตุสมผลในฐานะ enum การทำงานที่ดี!
David James

1
สุดยอด! ฉันมีความคิดที่จะสร้างสถานะที่ปรับแล้ว แต่มันไม่เกิดขึ้นกับฉันที่ฉันสามารถเปลี่ยนเป็นปรับวิธีการปรับได้ ขอบคุณ!
Adrian Harris Crowne

ตัวชี้ที่ยอดเยี่ยม ติดอยู่เล็กน้อยในเรื่องนี้ คำถามหนึ่งข้อ: เหตุผลใดที่คุณเพิ่มค่าผลตอบแทนของ Void ลงในฟังก์ชันปรับ?
jpittman

@jpittman เนื่องจากadjustฟังก์ชั่นส่งคืนVoidในExampleProtocolนั้นจะเหมือนกับการใช้mutating func adjust()ไฟล์. หากคุณต้องการadjustมีประเภทการส่งคืนคุณสามารถเปลี่ยนโปรโตคอลเป็น: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo

1
ไม่สามารถแก้ไขคำตอบเพื่อแก้ไขข้อผิดพลาดทางไวยากรณ์ไม่มีจุดควรเป็นcase .Base:
John Doe

45

นี่คือสิ่งที่ฉันทำ

เนื่องจากนี่คือ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

2
เพียงแค่ทราบว่าคุณสามารถลบ SimpleEnumeration ได้ปรับและแทนที่ด้วยเพียง ".Adjusted" หากชื่อของการแจงนับเคยเปลี่ยนไปการ refactor ก็มีน้อยลง
Shaolo

เย้ ๆ ๆ ดีกว่า ขอบคุณ.
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 Winter

7

นี่คือวิธีแก้ปัญหาที่ไม่เปลี่ยนค่า enum ปัจจุบัน แต่เป็นค่าอินสแตนซ์แทน (ในกรณีที่เป็นประโยชน์กับทุกคน)

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 ใน enums ดังนั้นจึงเป็นไปไม่ได้ที่จะมีตัวแปรที่คุณสามารถแก้ไขได้

คุณสามารถปฏิบัติตามโปรโตคอล แต่คุณไม่สามารถมีพฤติกรรมเดียวกันกับการกลายพันธุ์เหมือนในคลาสได้


2

เป็นลิงค์เกี่ยวกับ enum อย่างรวดเร็ว

โครงสร้างและการแจงนับเป็นประเภทมูลค่า ตามค่าเริ่มต้นคุณสมบัติของชนิดค่าไม่สามารถแก้ไขได้จากภายในวิธีการของอินสแตนซ์ ลิงค์

จากนั้นคุณต้องใช้ฟังก์ชันการกลายพันธุ์

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

อีกทางเลือกหนึ่งคือการปรับ () เพื่อพลิกระหว่างกรณีต่างๆดังนี้:

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

นี่คือคำตอบของ 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
        }
    }
}

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 ใน enum และมี enum พื้นฐานเริ่มต้น ดังนั้นคุณจะเห็นว่าเมื่อคุณสร้างวัตถุ enum เช่นในโครงสร้างและตัวอย่างคลาสใน Swift playground
อินทรรุส

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 ก่อนการทดลองนี้คำอธิบายง่ายๆจะหายไปภายใน - คุณไม่สามารถรับค่าดั้งเดิมกลับคืนมาได้ (เว้นแต่คุณจะบันทึกไว้นอกคลาส / โครงสร้าง) นี่คือสิ่งที่แจ้งให้ฉันสร้างเมธอด restore () สำหรับตัวอย่าง SimpleEnum ซึ่งช่วยให้คุณสามารถสลับไปมาระหว่างค่าต่างๆ หวังว่าจะเป็นประโยชน์กับใครบางคน!


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.