Làm thế nào để tạo một enum phù hợp với một giao thức trong Swift?


93

Tài liệu Swift nói rằng các lớp , cấu trúcenum đều có thể tuân theo các giao thức và tôi có thể đạt được điểm mà tất cả chúng đều tuân theo. Nhưng tôi không thể khiến enum hoạt động giống như các ví dụ về 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

Tôi chưa tìm ra cách nhận simpleDescriptionthay đổi do gọi điện adjust(). Ví dụ của tôi rõ ràng sẽ không làm điều đó bởi 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 một giá trị simpleDescriptiontrong khi vẫn tuân thủ ExampleProtocol?

Câu trả lời:


155

Đâ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

Điều này đáp ứng giao thức nhưng vẫn có ý nghĩa như một enum. Làm tốt lắm!
David James

1
Tuyệt vời! Tôi đã có ý tưởng tạo một trạng thái được điều chỉnh, nhưng tôi không thể thay đổi thành .Đ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. Đã một chút mắc kẹt về điều này. Tuy nhiên, một câu hỏi đặt ra: Bất kỳ lý do nào bạn thêm giá trị trả về của Void vào chức năng điều chỉnh?
jpittman

@jpittman vì adjusthàm trả về Voidtrong ExampleProtocol, nó giống như chỉ sử dụng mutating func adjust(). Nếu bạn muốn adjustcó loại trả lại, bạn có thể thay đổi giao thức thành: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo

1
Không thể chỉnh sửa câu trả lời để sửa lỗi cú pháp, nó thiếu một dấu chấm, nêncase .Base:
John Doe

44

Đây là ý kiến ​​của tôi.

Vì đây là một enumvà không phải a class, bạn phải nghĩ khác (TM) : đó là mô tả của bạn phải thay đổi khi "trạng thái" của bạn enumthay đổ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.


tôi đồng ý với việc bạn thực hiện chính enum và với mã bạn đã cung cấp. đẹp.

4
Câu trả lời này đẹp hơn và ngắn gọn hơn câu trả lời được chấp nhận.
Ricardo Sanchez-Saez

2
Chỉ cần một lưu ý nhỏ là bạn có thể loại bỏ SimpleEnumeration.Adjusted và thay thế chỉ bằng ".Adjusted". Nếu tên của bảng liệt kê luôn thay đổi thì chỉ cần cấu trúc lại là một điều đơn giản.
Shaolo

Vâng, điều này tốt hơn. Cảm ơn.
Arjun Kalidas

Mặc dù vậy, điều này không tuân theo giao thức đã cho
barry

11

Đâ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 tham quan 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 adjust()đóng vai trò như một nút chuyển đổi (mặc dù không có gì gợi ý về trường hợp này), hã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ề giao thức)


2
Tôi nghĩ cách tiếp cận này có lẽ là một trong những cách tốt nhất. Cập nhật nhanh là simpleDescription sẽ tự trở lại .rawValue
Justin Levi Winter

7

Đây là một giải pháp không thay đổi giá trị enum hiện tại mà thay vào đó là giá trị phiên bản của chúng (đề phòng trường hợp nó hữu í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

Điểm cộng cho ai tìm ra cách để tránh tất cả các công tắc đó. self = copy(self, self.desc + ", asdfasdf")
Vài

4

Không thể định nghĩa 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 việc thay đổi như trong các lớp.


2

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

Cấu trúc và kiểu liệt kê là các kiểu giá trị. Theo mặc định, các thuộc tính của 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

1

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

Đâ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

Tôi nghĩ ra cái này

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

đây là mã của tôi

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

Đóng góp đầu tiên của tôi ở đây:

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

Cảm ơn những người khác!


1
Bạn cũng có thể thêm một lời giải thích?
Robert

@Robert nó nên được tự giải thích như những người khác nhưng khác là tôi đang sử dụng phương thức init trong enum và có enum cơ bản mặc định. vì vậy bạn sẽ thấy điều đó khi bạn tạo đối tượng enum như trong cấu trúc và ví dụ lớp trong sân chơi Swift.
Indra Rusmita

0

Thử nghiệm này cũng khiến tôi thất vọng, do các ví dụ SimpleClass và SimpleStructure trước đó cho thấy thuộc tính simpleDescription đang được sửa đổi bên trong, điều này khiến tôi nghĩ rằng tôi cần phải làm điều tương tự. Sau khi xem qua các câu trả lời khác được đăng ở đây và đọc tài liệu chính thức của Apple Swift 2.1, tôi đã nghĩ ra điều này:

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

Cũng lưu ý rằng trong các ví dụ do Apple đưa ra cho SimpleClass và SimpleStructure trước thử nghiệm này, mô tả đơn giản bị mất bên trong - bạn không thể lấy lại giá trị ban đầu (tất nhiên trừ khi bạn lưu nó bên ngoài lớp / cấu trúc); đây là những gì đã thúc đẩy tôi tạo một phương thức restore () cho ví dụ SimpleEnum, cho phép bạn chuyển đổi nó qua lại giữa các giá trị. Hy vọng điều này là hữu ích cho ai đó!


0

Tôi đã nghĩ rằng mục tiêu chỉ đơn giản là giữ lại trạng thái và sử dụng mô tả để làm cho trạng thái hiện tại dễ đọc hơn:

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

Một biến thể khác: Sử dụng các giá trị được liên kết để giữ và hiển thị tùy chọn trước đó (có dạng "Đã chọn 1, điều chỉnh từ 2, điều chỉnh từ 1, điều chỉnh từ 2, điều chỉnh từ 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

Còn cái này thì sao

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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.