Câu hỏi Làm thế nào để thực hiện một enum phù hợp với một giao thức trong Swift?


Tài liệu Swift nói rằng các lớp học, cấu trúcenums tất cả có thể phù hợp với các giao thức, và tôi có thể đạt đến một điểm mà tất cả chúng đều phù hợp. Nhưng tôi không thể có được enum cư xử khá giống lớp học và cấu trúc ví dụ:

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

Tôi đã không tìm ra cách để có được simpleDescription để thay đổi như là kết quả của việc gọi adjust(). Ví dụ của tôi rõ ràng sẽ không làm điều đó vì getter có một giá trị được mã hóa cứng, nhưng làm cách nào tôi có thể đặt giá trị cho simpleDescription trong khi vẫn tuân theo ExampleProtocol?


76
2018-06-03 09:07


gốc




Các câu trả lời:


Đây là nỗ lực của tôi:

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

133
2018-06-04 08:35



Điều này đáp ứng các giao thức nhưng vẫn có ý nghĩa như một enum. Làm tốt lắm! - David James
Tuyệt vời! Tôi đã có ý tưởng tạo ra một trạng thái điều chỉnh, nhưng nó đã không xảy ra với tôi mà tôi có thể thay đổi. Điều chỉnh trong phương pháp điều chỉnh. Cảm ơn! - Adrian Harris Crowne
Con trỏ tuyệt vời. Có một chút bị mắc kẹt trên cái này. Một câu hỏi mặc dù: Bất kỳ lý do nào bạn thêm giá trị trả về của Void vào hàm điều chỉnh? - jpittman
@jpittman vì adjust chức năng trả về Void bên trong ExampleProtocol, nó cũng giống như chỉ sử dụng mutating func adjust(). Nếu bạn muốn adjust để có kiểu trả về, bạn có thể thay đổi giao thức thành: gist.github.com/anjerodesu/e1bf640576a3b6fa415f - Angelo
Không thể chỉnh sửa câu trả lời để sửa lỗi cú pháp, nó thiếu dấu chấm, phải là case .Base: - John Doe


Đây là của tôi lấy nó.

Vì đây là một enum và không phải là class, bạn phải nghĩ khác nhau (TM): đó là mô tả của bạn phải thay đổi khi "trạng thái" của bạn enum thay đổi (như được chỉ ra bởi @ 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

Hy vọng rằng sẽ giúp.


40
2018-06-04 10:52



tôi đồng ý với việc bạn lấy enum, và với mã bạn đã cung cấp. tốt đẹp.
Câu trả lời này đẹp hơn và gọn gàng hơn câu trả lời được chấp nhận. - Ricardo Sanchez-Saez
Chỉ cần lưu ý rằng bạn có thể xóa SimpleEnumeration.Adjusted và thay thế bằng chỉ ".Adjusted". Nếu tên của các liệt kê bao giờ thay đổi thì đó là một điều ít hơn để refactor. - Shaolo
Vâng, điều này tốt hơn. Cảm ơn. - Kruger Brent
Điều này không phù hợp với giao thức đã cho - barry


Đây là một cách tiếp cận khác, chỉ sử dụng kiến ​​thức thu được từ chuyến lưu diễn cho đến thời điểm đó *

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

Nếu bạn muốn có adjust() hoạt động như một chuyển đổi (mặc dù không có gì để đề xuất trường hợp này), sử dụng:

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

* (Mặc dù nó không đề cập rõ ràng cách chỉ định kiểu trả về  một giao thức)


11
2018-06-12 16:04



Tôi nghĩ rằng cách tiếp cận này có lẽ là cách tốt nhất của nhóm. Cập nhật nhanh chóng là simpleDescription phải trả về self.rawValue - Justin Levi Winter


Đây là một giải pháp không thay đổi giá trị enum hiện tại, nhưng thay vào đó các giá trị của chúng (chỉ trong trường hợp nó có ích cho bất kỳ ai).

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

7
2018-06-13 23:16



Điểm thêm cho bất cứ ai tìm cách tránh tất cả các công tắc đó. Một cái gì đó dọc theo dòng của bản sao hư cấu này self = copy(self, self.desc + ", asdfasdf") - DiogoNeves


Không thể xác định các biến mà không có getter và setter trong enums và do đó không thể có một biến mà bạn có thể sửa đổi.

Bạn có thể tuân theo giao thức nhưng bạn không thể có hành vi tương tự với đột biến như trong các lớp học.


4
2018-06-03 11:07





Nó là một liên kết về enum nhanh chóng.

Cấu trúc và liệt kê là các loại giá trị. Theo mặc định, các thuộc tính của một kiểu giá trị không thể được sửa đổi từ bên trong các phương thức thể hiện của nó. liên kết

Sau đó, bạn phải sử dụng chức năng đột biến.

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

2
2018-06-13 03:48





Một tùy chọn khác là điều chỉnh () để lật giữa các trường hợp như sau:

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
2018-06-08 12:19





Đây là câu trả lời của 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
2018-01-15 14:53