Özel başlatıcı ile Swift enum rawValue başlatıcısını kaybeder


96

Aşağıdakilerle bu konuyu en basit haline getirmeye çalıştım.

Kurmak

Xcode Sürümü 6.1.1 (6A2008a)

Şu şekilde tanımlanan bir enum MyEnum.swift:

internal enum MyEnum: Int {
    case Zero = 0, One, Two
}

extension MyEnum {
    init?(string: String) {
        switch string.lowercaseString {
        case "zero": self = .Zero
        case "one": self = .One
        case "two": self = .Two
        default: return nil
        }
    }
}

ve numaralandırmayı başka bir dosyada başlatan kod MyClass.swift:

internal class MyClass {
    let foo = MyEnum(rawValue: 0)  // Error
    let fooStr = MyEnum(string: "zero")

    func testFunc() {
        let bar = MyEnum(rawValue: 1)  // Error
        let barStr = MyEnum(string: "one")
    }
}

Hata

Xcode MyEnum, ham değer başlatıcısı ile başlatmaya çalışırken bana şu hatayı veriyor :

Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'

Notlar

  1. Başına Swift Dil Rehberi :

    Bir ham değer türü ile bir numaralandırma tanımlarsanız, numaralandırma otomatik olarak ham değerin türünün değerini (çağrılan bir parametre olarak rawValue) alan ve bir numaralandırma üyesi veya döndüren bir başlatıcı alır nil.

  2. İçin özel başlatıcı MyEnum, numaralandırmanın ham değer başlatıcısının aşağıdaki durum nedeniyle Dil Kılavuzundan kaldırılıp kaldırılmadığını test etmek için bir uzantıda tanımlandı . Ancak aynı hata sonucunu elde eder.

    Bir değer türü için özel bir başlatıcı tanımlarsanız, artık o tür için varsayılan başlatıcıya (veya bir yapıysa üye başlatıcıya) erişemeyeceğinizi unutmayın. [...]
    Özel değer türünüzün varsayılan başlatıcı ve üye başlatıcı ile ve ayrıca kendi özel başlatıcılarınızla başlatılabilir olmasını istiyorsanız, özel başlatıcılarınızı değer türünün orijinal uygulamasının bir parçası yerine bir uzantı olarak yazın.

  3. Enum tanımının taşınması, MyClass.swifthatayı çözer, barancak için çözmez foo.

  4. Özel başlatıcıyı kaldırmak her iki hatayı da çözer.

  5. Çözümlerden biri, aşağıdaki işlevi enum tanımına dahil etmek ve sağlanan ham değer başlatıcısı yerine kullanmaktır. Bu nedenle, özel bir başlatıcı eklemenin ham değer başlatıcıyı işaretlemeye benzer bir etkisi varmış gibi görünüyor private.

    init?(raw: Int) {
        self.init(rawValue: raw)
    }
    
  6. Açıkça protokol uygunluğunu beyan RawRepresentableiçinde MyClass.swiftgiderir satır içi hatası bar, ancak yinelenen simgeleri hakkında bir bağlayıcı hatası sonuçları (ham-değer türü çeteleler örtülü uygun çünkü RawRepresentable).

    extension MyEnum: RawRepresentable {}
    

Burada neler olup bittiğine dair biraz daha bilgi veren var mı? Ham değer başlatıcı neden erişilebilir değil?


Bu konuda bir hata dosyalamanız gerekir - varsayılan başlatıcıların internalkapsamı olmalıdır (veya en azından türle eşleşmelidir), değil private.
Nate Cook

Ben de tamamen aynı sorunu yaşıyorum. Özel bir başlatıcı oluşturduğumda varsayılan olan kayboldu
Yariv Nissim

Bana böcek gibi kokuyor.
akashivskyy

2
Şüphelerimi doğruladığınız için teşekkürler. Bu bir hata olarak kaydedildi.
nickgraef

5 numara benim için yaptı.
Andrew Duncan

Yanıtlar:


26

Bu hata Xcode 7 ve Swift 2'de çözüldü


25
Bu tür yanıtlar, gelecekteki ziyaretçilerin konunun durumunu kontrol edebilmesi için ilişkili bilete bir bağlantıdan yararlanır.
Raphael

14
extension TemplateSlotType {
    init?(rawString: String) {
        // Check if string contains 'carrousel'
        if rawString.rangeOfString("carrousel") != nil {
            self.init(rawValue:"carrousel")
        } else {
            self.init(rawValue:rawString)
        }
    }
}

Sizin durumunuzda bu, aşağıdaki uzantı ile sonuçlanır:

extension MyEnum {
    init?(string: String) {
        switch string.lowercaseString {
        case "zero": 
            self.init(rawValue:0)
        case "one": 
            self.init(rawValue:1)
        case "two":
            self.init(rawValue:2)
        default: 
            return nil
        }
    }
}

7

Hatta kodu switchvakalar olmadan daha basit ve kullanışlı hale getirebilirsiniz , bu şekilde yeni bir tür eklerken daha fazla durum eklemenize gerek kalmaz.

enum VehicleType: Int, CustomStringConvertible {
    case car = 4
    case moped = 2
    case truck = 16
    case unknown = -1

    // MARK: - Helpers

    public var description: String {
        switch self {
        case .car: return "Car"
        case .truck: return "Truck"
        case .moped: return "Moped"
        case .unknown: return "unknown"
        }
    }

    static let all: [VehicleType] = [car, moped, truck]

    init?(rawDescription: String) {
        guard let type = VehicleType.all.first(where: { description == rawDescription })
            else { return nil }
        self = type
    }
}

1

Evet bu can sıkıcı bir konu. Şu anda bir fabrika olarak işlev gören küresel kapsamlı bir işlev kullanarak bunun üzerinde çalışıyorum

func enumFromString(string:String) -> MyEnum? {
    switch string {
    case "One" : MyEnum(rawValue:1)
    case "Two" : MyEnum(rawValue:2)
    case "Three" : MyEnum(rawValue:3)
    default : return nil
    }
}

1

Bu, EnumSequence'ımla birlikte Xcode 9.2'de Swift 4 için çalışır :

enum Word: Int, EnumSequenceElement, CustomStringConvertible {
    case apple, cat, fun

    var description: String {
        switch self {
        case .apple:
            return "Apple"
        case .cat:
            return "Cat"
        case .fun:
            return "Fun"
        }
    }
}

let Words: [String: Word] = [
    "A": .apple,
    "C": .cat,
    "F": .fun
]

extension Word {
    var letter: String? {
        return Words.first(where: { (_, word) -> Bool in
            word == self
        })?.key
    }

    init?(_ letter: String) {
        if let word = Words[letter] {
            self = word
        } else {
            return nil
        }
    }
}

for word in EnumSequence<Word>() {
    if let letter = word.letter, let lhs = Word(letter), let rhs = Word(letter), lhs == rhs {
        print("\(letter) for \(word)")
    }
}

Çıktı

A for Apple
C for Cat
F for Fun

-1

Bunu kodunuza ekleyin:

extension MyEnum {
    init?(rawValue: Int) {
        switch rawValue {
        case 0: self = .Zero
        case 1: self = .One
        case 2: self = .Two
        default: return nil
        }
    }
}

Bunun yerine Int uzatabilir misin? Daha kolay gibi görünüyor.
ericgu
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.