Bir numaralandırma, Swift'deki bir protokole nasıl uydurulur?


97

Swift dokümantasyonu, sınıfların , yapıların ve numaralandırmaların tümünün protokollere uyabileceğini ve hepsinin uyumlu olduğu bir noktaya gelebileceğimi söylüyor . Ancak numaralandırmanın sınıf ve yapı örnekleri gibi davranmasını sağlayamıyorum :

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

Aramanın simpleDescriptionbir sonucu olarak nasıl değiştirileceğini bulamadım adjust(). Örneğim açıkça bunu yapmayacak çünkü alıcının sabit kodlu bir değeri var, ancak simpleDescriptionhala ExampleProtocol?

Yanıtlar:


157

Bu benim girişimim:

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

Bu, protokolü karşılar ancak yine de bir sıralama olarak mantıklıdır. İyi iş!
David James

1
Harika! Ayarlanmış bir durum oluşturma fikrim vardı, ancak değiştirebileceğim aklıma gelmedi. Ayarlama yönteminde ayarlandı. Teşekkürler!
Adrian Harris Crowne

Mükemmel işaretçi. Bunda biraz sıkışıp kaldım. Yine de bir soru: Void'in dönüş değerini ayarlama işlevine eklemenizin herhangi bir nedeni var mı?
jpittman

@jpittman nedeniyle adjustişlevini verir Voidde ExampleProtocol, sadece kullanılarak aynıdır mutating func adjust(). adjustBir dönüş türüne sahip olmak istiyorsanız , protokolü şu şekilde değiştirebilirsiniz: gist.github.com/anjerodesu/e1bf640576a3b6fa415f
Angelo

1
Sözdizimi hatasını düzeltmek için yanıt düzenlenemedi, bir nokta eksik, şöyle olmalıcase .Base:
John Doe,

45

İşte benim almam.

Bu bir enuma değil class, farklı düşünmek zorundasınız (TM) : değişikliklerinizin "durumu" enum(@ hu-qiang tarafından belirtildiği gibi) değiştiğinde değişmesi gereken tanımınızdır.

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

Umarım yardımcı olur.


Sıralamanın kendisine ve sağladığınız koda katılıyorum. Güzel.

4
Bu cevap, kabul edilenden daha güzel ve daha kısa.
Ricardo Sanchez-Saez

2
SimpleEnumeration.Adjusted'ı kaldırabileceğinizi ve sadece ".Adjusted" ile değiştirebileceğinizi unutmayın. Numaralandırmanın adı değişirse, yeniden düzenleme yapmak daha az şey olur.
Shaolo

Evet, bu daha iyi. Teşekkürler.
Arjun Kalidas

Bu, verilen protokole uymuyor
barry

11

İşte sadece turdan o noktaya kadar kazanılan bilgileri kullanan başka bir yaklaşı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

adjust()Geçiş olarak hareket etmek istiyorsanız (bunun böyle olduğunu önerecek hiçbir şey olmamasına rağmen), şunu kullanın:

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

* (Bir dönüş türünün ve protokolün nasıl belirtileceğini açıkça belirtmese de )


2
Bence bu yaklaşım muhtemelen grubun en iyisi. Hızlı güncelleme, simpleDescription'ın self.rawValue döndürmesi gerektiğidir
Justin Levi Winter

7

İşte mevcut enum değerini değiştirmeyen, bunun yerine örnek değerlerini değiştiren bir çözüm (herkes için yararlı olması durumunda).

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

Tüm bu değişikliklerden kaçınmanın bir yolunu bulanlara ekstra puan. Bu hayali kopyanın şey satırlarıself = copy(self, self.desc + ", asdfasdf")
DiogoNeves

4

Numaralandırmalarda alıcı ve ayarlayıcı olmadan değişkenleri tanımlamak mümkün değildir ve bu nedenle değiştirebileceğiniz bir değişkene sahip olmak imkansızdır.

Protokole uyabilirsiniz, ancak sınıflarda olduğu gibi mutating ile aynı davranışa sahip olamazsınız.


2

Swift ile enum hakkında bir bağlantıdır .

Yapılar ve numaralandırmalar değer türleridir. Varsayılan olarak, bir değer türünün özellikleri, örnek yöntemleri içinden değiştirilemez. bağlantı

Ardından, mutasyon işlevini kullanmalısınız.

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

Diğer bir seçenek de, aşağıdaki gibi durumlar arasında geçiş yapmak için ayar () içindir:

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

İşte Jack'in cevabına dayanarak:

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

Bununla geldim

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

işte kodum

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

Buradaki ilk katkım:

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

Başkaları için teşekkürler!


1
Bir açıklama da ekleyebilir misiniz?
Robert

@Robert, diğerleri gibi kendi kendine açıklanmalı, ancak farklı olan, enum'da init yöntemini kullanıyorum ve varsayılan temel numaralandırmaya sahip olmam. Böylece Swift oyun alanında yapı ve sınıf örneğinde olduğu gibi bir numaralandırma nesnesi oluşturduğunuzda göreceksiniz.
Indra Rusmita

0

SimpleDescription özelliğinin dahili olarak değiştirildiğini gösteren önceki SimpleClass ve SimpleStructure örneklerinden dolayı bu deney beni de etkisiz hale getirdi ve bu da aynı şeyi yapmam gerektiğini düşünmeme neden oldu. Burada yayınlanan diğer cevaplara baktıktan ve resmi Apple Swift 2.1 belgelerini okuduktan sonra şunu buldum:

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

Ayrıca, Apple tarafından SimpleClass ve SimpleStructure için bu deneyden önce verilen örneklerde, basit açıklamanın dahili olarak kaybolduğuna dikkat edin - orijinal değeri geri alamazsınız (tabii ki sınıfın / yapının dışında kaydetmediğiniz sürece); SimpleEnum örneği için değerler arasında ileri ve geri geçiş yapmanıza izin veren bir restore () yöntemi oluşturmamı sağlayan şey buydu. Umarım bu birisi için yararlıdır!


0

Hedefin basitçe durumu korumak ve mevcut durumu okumayı kolaylaştırmak için bir açıklama kullanmak olduğunu düşünüyordum:

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

Başka bir varyasyon: Önceki seçeneği tutmak ve görüntülemek için ilişkili değerleri kullanma ("Seçildi 1, 2'den ayarlanmış, 1'den ayarlanmış, 2'den ayarlanmış, 1'den ayarlanmış" biçiminde)

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

buna ne dersin

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"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.