कस्टम इनिलाइज़र के साथ स्विफ्ट एनम रॉवेल्यू इनिशियलाइज़र खो देता है


95

मैंने इस मुद्दे को निम्नलिखित के साथ अपने सबसे सरल रूप में उबालने की कोशिश की है।

सेट अप

Xcode संस्करण 6.1.1 (6A2008a)

में परिभाषित एक एनम 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
        }
    }
}

और कोड जो किसी अन्य फ़ाइल में enum को इनिशियलाइज़ करता है 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")
    }
}

त्रुटि

MyEnumअपने कच्चे-मूल्य इनिशियलाइज़र के साथ आरंभ करने का प्रयास करते समय Xcode मुझे निम्न त्रुटि देता है:

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

टिप्पणियाँ

  1. प्रति स्विफ्ट भाषा गाइड :

    यदि आप एक कच्चे-प्रकार के प्रकार के साथ एक गणना को परिभाषित करते हैं, तो गणन स्वचालित रूप से एक आरम्भक प्राप्त करता है जो कच्चे मान के प्रकार (जैसा कि एक पैरामीटर कहा जाता है rawValue) का मान लेता है और या तो एक गणना सदस्य या देता है nil

  2. के लिए कस्टम इनिशियलाइज़र MyEnumको यह जांचने के लिए एक विस्तार में परिभाषित किया गया था कि भाषा गाइड से निम्नलिखित मामले के कारण एनम के कच्चे-मूल्य इनिशियलाइज़र को हटाया जा रहा है या नहीं । हालाँकि, यह समान त्रुटि परिणाम प्राप्त करता है।

    ध्यान दें कि यदि आप मूल्य प्रकार के लिए एक कस्टम इनिशियलाइज़र को परिभाषित करते हैं, तो आपके पास उस प्रकार के लिए अब डिफ़ॉल्ट इनिशियलाइज़र (या सदस्यवार इनिशियलाइज़र, यदि यह एक संरचना है) तक पहुँच नहीं होगी। [...]
    यदि आप चाहते हैं कि आपका कस्टम वैल्यू टाइप डिफॉल्ट इनिशियलाइज़र और मेंडवाइज़र इनिशियलाइज़र के साथ तुलनात्मक हो और अपने स्वयं के कस्टम इनिशियलाइज़र के साथ भी, तो आप अपने कस्टम इनिशियलाइज़र को वैल्यू टाइप के मूल कार्यान्वयन के भाग के बजाय एक एक्सटेंशन में लिखें।

  3. के MyClass.swiftलिए barनहीं बल्कि त्रुटि को हल करने के लिए एनम परिभाषा को आगे बढ़ाना foo

  4. कस्टम इनिशियलाइज़र को हटाने से दोनों त्रुटियां हल हो जाती हैं।

  5. एक समाधान यह है कि एनुम परिभाषा में निम्नलिखित फ़ंक्शन को शामिल करें और इसे प्रदान किए गए कच्चे-मूल्य इनिशियलाइज़र के स्थान पर उपयोग करें। तो ऐसा लगता है जैसे कि कस्टम इनिशियलाइज़र को जोड़ने से रॉ-वैल्यू इनिशियलाइज़र को चिह्नित करने के समान प्रभाव पड़ता है private

    init?(raw: Int) {
        self.init(rawValue: raw)
    }
  6. स्पष्ट रूप से के लिए इनलाइन त्रुटि RawRepresentableको MyClass.swiftहल करने के लिए प्रोटोकॉल अनुरूपता की घोषणा की bar, लेकिन डुप्लिकेट प्रतीकों के बारे में एक लिंकर त्रुटि में परिणाम (क्योंकि कच्चे-प्रकार के प्रकार अंतर्निहित रूप से अनुरूप हैं RawRepresentable)।

    extension MyEnum: RawRepresentable {}

किसी को भी यहाँ क्या हो रहा है में थोड़ा और अंतर्दृष्टि प्रदान कर सकते हैं? कच्चे-मूल्य इनिशियलाइज़र सुलभ क्यों नहीं है?


आपको इस पर एक बग दर्ज करना चाहिए - डिफ़ॉल्ट आरंभीकरण में internalगुंजाइश होनी चाहिए (या कम से कम प्रकार से मेल खाना चाहिए ), नहीं private
नैट कुक

मुझे ठीक वैसी ही समस्या हो रही है। एक बार जब मैं एक कस्टम इनिशियलाइज़र बनाता हूँ तो डिफ़ॉल्ट एक
यारिव निसिम

मेरे लिए एक बग की तरह खुशबू आ रही है।
akashivskyy

2
मेरे संदेह को मान्य करने के लिए धन्यवाद। यह एक बग के रूप में दायर किया गया है।
निकरैफ

नंबर 5 ने मेरे लिए किया।
एंड्रयू डंकन

जवाबों:


25

यह बग Xcode 7 और Swift 2 में हल किया गया है


24
संबंधित टिकट के लिंक से इस तरह के लाभ के उत्तर ताकि भविष्य के आगंतुक मामले की स्थिति की जांच कर सकें।
राफेल

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)
        }
    }
}

आपके मामले में यह निम्नलिखित विस्तार में परिणाम होगा:

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

आप switchमामलों के बिना भी कोड को सरल और उपयोगी बना सकते हैं, इस तरह आपको नए प्रकार जोड़ने पर अधिक मामलों को जोड़ने की आवश्यकता नहीं है।

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

हाँ यह एक कष्टप्रद मुद्दा है। मैं वर्तमान में इसके चारों ओर काम कर रहा हूं जो एक वैश्विक-गुंजाइश फ़ंक्शन का उपयोग करता है जो एक कारखाने के रूप में कार्य करता है, अर्थात

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
    }
}

0

यह मेरी EnumSequence के साथ Xcode 9.2 पर स्विफ्ट 4 के लिए काम करता है :

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)")
    }
}

उत्पादन

A for Apple
C for Cat
F for Fun

-1

इसे अपने कोड में जोड़ें:

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

क्या आप इसके बजाय इंट का विस्तार कर सकते हैं? लगता है अपने आसान है।
एरिकगु
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.