स्विफ्ट में गणना मूल्य का नाम कैसे प्राप्त करें?


167

अगर मेरे पास कच्चे Integerमूल्यों के साथ एक गणना है :

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa
}

let city = City.Melbourne

मैं किसी cityमान को स्ट्रिंग में कैसे बदल सकता हूं Melbourne? क्या भाषा में इस प्रकार का नाम आत्मनिरीक्षण उपलब्ध है?

कुछ इस तरह (यह कोड काम नहीं करेगा):

println("Your city is \(city.magicFunction)")
> Your city is Melbourne

जवाबों:


139

Xcode 7 बीटा 5 (स्विफ्ट संस्करण 2) के रूप में, अब आप डिफ़ॉल्ट रूप से टाइप नाम और एनम मामलों को प्रिंट कर सकते हैं print(_:), या 's initializer या स्ट्रिंग इंटरपोलेशन सिंटैक्स ' का Stringउपयोग करके परिवर्तित कर सकते हैं । तो आपके उदाहरण के लिए:Stringinit(_:)

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne

print(city)
// prints "Melbourne"

let cityName = "\(city)"   // or `let cityName = String(city)`
// cityName contains "Melbourne"

इसलिए एक स्ट्रिंग फ़ंक्शन को वापस लौटने के लिए प्रत्येक मामले पर स्विच करने वाले एक सुविधा फ़ंक्शन को परिभाषित करने और बनाए रखने की आवश्यकता नहीं है। इसके अलावा, यह किसी भी एनम के लिए स्वचालित रूप से काम करता है, भले ही कोई कच्चा-मूल्य प्रकार निर्दिष्ट नहीं किया गया हो।

debugPrint(_:)और String(reflecting:)पूरी तरह से योग्य नाम के लिए इस्तेमाल किया जा सकता है:

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

ध्यान दें कि आप इनमें से प्रत्येक परिदृश्य में जो छपा है उसे कस्टमाइज़ कर सकते हैं:

extension City: CustomStringConvertible {
    var description: String {
        return "City \(rawValue)"
    }
}

print(city)
// prints "City 1"

extension City: CustomDebugStringConvertible {
    var debugDescription: String {
        return "City (rawValue: \(rawValue))"
    }
}

debugPrint(city)
// prints "City (rawValue: 1)"

(मुझे इस "डिफ़ॉल्ट" मूल्य में कॉल करने का एक तरीका नहीं मिला है, उदाहरण के लिए, "शहर मेलबर्न है" को एक स्विच स्टेटमेंट के लिए वापस लेने के बिना प्रिंट \(self)करने के लिए description/ debugDescriptionएक अनंत पुनरावर्तन का उपयोग करता है।


ऊपर टिप्पणी Stringकी init(_:)और init(reflecting:)initializers, का वर्णन वास्तव में क्या छपा है क्या परिलक्षित प्रकार अनुरूप पर निर्भर करता है:

extension String {
    /// Initialize `self` with the textual representation of `instance`.
    ///
    /// * If `T` conforms to `Streamable`, the result is obtained by
    ///   calling `instance.writeTo(s)` on an empty string s.
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
    ///   result is `instance`'s `description`
    /// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
    ///   the result is `instance`'s `debugDescription`
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(reflecting: T)`
    public init<T>(_ instance: T)

    /// Initialize `self` with a detailed textual representation of
    /// `subject`, suitable for debugging.
    ///
    /// * If `T` conforms to `CustomDebugStringConvertible`, the result
    ///   is `subject`'s `debugDescription`.
    ///
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
    ///   is `subject`'s `description`.
    ///
    /// * Otherwise, if `T` conforms to `Streamable`, the result is
    ///   obtained by calling `subject.writeTo(s)` on an empty string s.
    ///
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(T)`
    public init<T>(reflecting subject: T)
}


इस परिवर्तन के बारे में जानकारी के लिए रिलीज़ नोट देखें ।


8
इसके अलावा अगर आप बिना इस्तेमाल किए स्ट्रिंग मूल्य चाहते print(enum)हैंString(enum)
Kametrixom

44
महत्वपूर्ण पकड़, यह केवल स्विफ्ट एनम के लिए काम करता है। यदि आप OS X पर बाइंडिंग समर्थन की अनुमति देने के लिए इसे @objc टैग करते हैं, तो यह काम नहीं करेगा।
क्लॉस जोर्जेंसन

11
महान स्विफ्ट-विशिष्ट उत्तर; हालाँकि, यदि आपको गैर-स्विफ्ट एनम पर ऐसा करने की आवश्यकता है, जैसे कि CLAuthorizationStatusअपने locationManager didChangeAuthorizationStatusप्रतिनिधि कॉलबैक के अंदर (ऑब्जेक्टिव सी) एनम के मूल्य को प्रिंट करने के लिए , आपको एक प्रोटोकॉल एक्सटेंशन को परिभाषित करने की आवश्यकता होगी। उदाहरण के लिए: extension CLAuthorizationStatus: CustomStringConvertable { public var description: String { switch self { case .AuthorizedAlways: return "AuthorizedAlways" <etc> } } }- एक बार जब आप ऐसा कर लेते हैं, तो यह काम करना चाहिए जैसा कि आप अपेक्षा करते हैं: प्रिंट ("प्रामाणिक स्थिति: (\ स्थिति))"।
जेफ्रो

3
"एक्सकोड 7 बीटा 5 के रूप में" अर्थहीन है। यह Xcode नहीं है जो इसमें से किसी को भी परिभाषित करता है, यह स्विफ्ट कंपाइलर और स्विफ्ट रनटाइम लीबरीज है। मैं Xcode 9.3 का उपयोग कर सकता हूं लेकिन मेरा कोड अभी भी स्विफ्ट 3 हो सकता है और फिर मैं स्विफ्ट 4 सुविधाओं का उपयोग करने में सक्षम नहीं होगा। Xcode 9.3 का उपयोग करते हुए, यह कोड Xcode 9.3 Xcode 7. की तुलना में बहुत नया होने के बावजूद काम नहीं करता है
Mecki

8
मुझे इनिशियलाइज़र 'init (_ :)' की आवश्यकता है कि सिटी को 'डायोडलेसस्ट्रिंगकॉनवर्टिबल' के अनुरूप Xcode 10.2, स्विफ्ट 5. के अनुरूप होना चाहिए। अब हम इसे कैसे करते हैं?
रॉकगैको

73

फिलहाल एनम मामलों पर कोई आत्मनिरीक्षण नहीं है। आपको उन्हें प्रत्येक को मैन्युअल रूप से घोषित करना होगा:

enum City: String, CustomStringConvertible {
    case Melbourne = "Melbourne"
    case Chelyabinsk = "Chelyabinsk"
    case Bursa = "Bursa"

    var description: String {
        get {
            return self.rawValue
        }
    }
}

यदि आपको इंट होने के लिए कच्चे प्रकार की आवश्यकता है, तो आपको स्वयं एक स्विच करना होगा:

enum City: Int, CustomStringConvertible {
  case Melbourne = 1, Chelyabinsk, Bursa

  var description: String {
    get {
      switch self {
        case .Melbourne:
          return "Melbourne"
        case .Chelyabinsk:
          return "Chelyabinsk"
        case .Bursa:
          return "Bursa"
      }
    }
  }
}

2
नॉब का सवाल है, लेकिन सिर्फ रिटर्न सेल्फ रिटर्न के बजाय {रिटर्न सेल्फ.वैलव्यू} क्यों डाला जाए? मैंने बाद की कोशिश की और यह ठीक काम करता है।
चक कृत्सिंगर

get { ... }यदि आप एक सेटर को परिभाषित नहीं करते हैं, तो आप संक्षिप्तता के लिए भाग को भी छोड़ सकते हैं ।
Iosdude

1
महान जवाब के लिए धन्यवाद। Xcode 7.3 में, मुझे मिलता है: "Printable का नाम बदलकर CustomStringConvertible" कर दिया गया है। समाधान आसान है - ऊपर दिए गए पहले कोड उदाहरण में, पहली पंक्ति को बदल दें enum City : String, CustomStringConvertible {। CSC प्रोटोकॉल के एक हिस्से के रूप में, आपको फिर सार्वजनिक होने के लिए संपत्ति को बदलना होगा :public var description : String {
जेफ्रो

44

स्विफ्ट -3 (Xcode 8.1 के साथ परीक्षण किया गया) में आप अपने एनम में निम्नलिखित तरीके जोड़ सकते हैं:

/**
 * The name of the enumeration (as written in case).
 */
var name: String {
    get { return String(describing: self) }
}

/**
 * The full name of the enumeration
 * (the name of the enum plus dot plus the name as written in case).
 */
var description: String {
    get { return String(reflecting: self) }
}

फिर आप इसे अपने एनम उदाहरण पर एक सामान्य विधि कॉल के रूप में उपयोग कर सकते हैं। यह पिछले स्विफ्ट संस्करणों में भी काम कर सकता है, लेकिन मैंने इसका परीक्षण नहीं किया है।

आपके उदाहरण में:

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
    var name: String {
        get { return String(describing: self) }
    }
    var description: String {
        get { return String(reflecting: self) }
    }
}
let city = City.Melbourne

print(city.name)
// prints "Melbourne"

print(city.description)
// prints "City.Melbourne"

यदि आप अपने सभी एनमों को यह कार्यक्षमता प्रदान करना चाहते हैं, तो आप इसे बढ़ा सकते हैं:

/**
 * Extend all enums with a simple method to derive their names.
 */
extension RawRepresentable where RawValue: Any {
  /**
   * The name of the enumeration (as written in case).
   */
  var name: String {
    get { return String(describing: self) }
  }

  /**
   * The full name of the enumeration
   * (the name of the enum plus dot plus the name as written in case).
   */
  var description: String {
    get { return String(reflecting: self) }
  }
}

यह केवल स्विफ्ट एनम के लिए काम करता है।


18

उद्देश्य-सी के enumलिए वर्तमान में एकमात्र तरीका प्रतीत होता है, उदाहरण के लिए, एनम को विस्तारित करने के लिए CustomStringConvertibleकुछ के साथ समाप्त करना:

extension UIDeviceBatteryState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .Unknown:
            return "Unknown"
        case .Unplugged:
            return "Unplugged"
        case .Charging:
            return "Charging"
        case .Full:
            return "Full"
        }
    }
}

और फिर कास्टिंग के enumरूप में String:

String(UIDevice.currentDevice().batteryState)

12

String(describing:)प्रारंभकर्ता यहां तक कि गैर-स्ट्रिंग rawValues साथ enums के लिए मामला लेबल नाम वापस जाने के लिए इस्तेमाल किया जा सकता:

enum Numbers: Int {
    case one = 1
    case two = 2
}

let one = String(describing: Numbers.one) // "one"
let two = String(describing: Numbers.two) // "two"

ध्यान दें कि अगर एनम संशोधक का उपयोग करता है तो यह काम नहीं करता है @objc:

https://forums.swift.org/t/why-is-an-enum-returning-enumname-rather-than-caselabel-for-string-describing/27327

ऑब्जेक्टिव-सी प्रकारों के लिए उत्पन्न स्विफ्ट इंटरफेस कभी-कभी @objcसंशोधक को शामिल नहीं करते हैं। उन Enums को अभी भी Objective-C में परिभाषित किया गया है, और इस प्रकार ऊपर की तरह काम नहीं करते हैं।


7

स्विफ्ट 2.2 में Enums के लिए स्ट्रिंग (…) (CustomStringConvertible) समर्थन के शीर्ष पर, उनके लिए कुछ हद तक टूटा हुआ प्रतिबिंब समर्थन भी है। संबंधित मूल्यों के साथ एनम मामलों के लिए प्रतिबिंब का उपयोग करके एनम मामले का लेबल प्राप्त करना संभव है:

enum City {
    case Melbourne(String)
    case Chelyabinsk
    case Bursa

    var label:String? {
        let mirror = Mirror(reflecting: self)
        return mirror.children.first?.label
    }
}

print(City.Melbourne("Foobar").label) // prints out "Melbourne"

टूटने से, मेरा मतलब है कि "सरल" शब्दों के लिए, उपरोक्त प्रतिबिंब आधारित labelगणना की गई संपत्ति सिर्फ रिटर्न देती हैnil (बू-हू) है।

print(City.Chelyabinsk.label) // prints out nil

जाहिरा तौर पर स्विफ्ट 3 के बाद प्रतिबिंब की स्थिति बेहतर होनी चाहिए। हालांकि इसका समाधान String(…)अन्य उत्तरों में से एक में सुझाया गया है:

print(String(City.Chelyabinsk)) // prints out Cheylabinsk

2
ऐसा लगता है कि यह वैकल्पिक बनाने की आवश्यकता के बिना स्विफ्ट 3.1 पर काम करता है:var label:String { let mirror = Mirror(reflecting: self); if let label = mirror.children.first?.label { return label } else { return String(describing:self) } }
डेविड जेम्स

5

यह बहुत निराशाजनक है।

उस मामले के लिए जब आपको उन नामों की आवश्यकता होती है (ताकि कंपाइलर को पूरी तरह से वर्तनी की सही जानकारी हो, लेकिन उसे उपयोग करने से मना कर दें - धन्यवाद स्विफ्ट टीम !! -) लेकिन नहीं चाहते हैं या स्ट्रिंग को आपके एनम का आधार नहीं बना सकते हैं, एक !!! क्रिया, बोझिल विकल्प इस प्रकार है:

enum ViewType : Int, Printable {

    case    Title
    case    Buttons
    case    View

    static let all = [Title, Buttons, View]
    static let strings = ["Title", "Buttons", "View"]

    func string() -> String {
        return ViewType.strings[self.rawValue]
    }

    var description:String {
        get {
            return string()
        }
    }
}

आप निम्नानुसार उपयोग कर सकते हैं:

let elementType = ViewType.Title
let column = Column.Collections
let row = 0

println("fetching element \(elementType), column: \(column.string()), row: \(row)")

और आपको अपेक्षित परिणाम मिलेगा (समान कॉलम के लिए कोड, लेकिन दिखाया नहीं गया)

fetching element Title, column: Collections, row: 0

उपरोक्त में, मैंने बनाया है description संपत्ति को stringविधि में वापस कर दिया है, लेकिन यह स्वाद का मामला है। यह भी ध्यान दें कि तथाकथितstatic वैरिएबल को उनके संलग्न प्रकार के नाम से योग्य होने की आवश्यकता है, क्योंकि कंपाइलर बहुत अधिक सामान्य है और सभी द्वारा संदर्भ को याद नहीं किया जा सकता है ...

स्विफ्ट टीम को वास्तव में आज्ञा दी जानी चाहिए। उन्होंने यह माना कि आप ऐसा नहीं कर सकते हैं enumerateऔर जिस पर आप प्रयोग कर सकते enumerateहैं वह "अनुक्रम" है लेकिन नहीं enum!


ऐसा लगता है कि लंबे समय से वर्णन में केवल स्ट्रिंग (परावर्तित: स्व) वापसी की तुलना में लंबे समय से घुमावदार है।
बून

4

मैं इस सवाल से टकरा गया और बताए गए मैजिकफंक्शन को बनाने के लिए एक सरल तरीका साझा करना चाहता था

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa

    func magicFunction() -> String {
        return "\(self)"
    }
}

let city = City.Melbourne
city.magicFunction() //prints Melbourne

3

स्विफ्ट के पास अब इम्प्लिमेंटली असाइन्ड रॉ वैल्यू के रूप में जाना जाता है । मूल रूप से यदि आप प्रत्येक मामले में कच्चे मान नहीं देते हैं और एनम टाइप स्ट्रिंग का है, तो यह इस बात को काटता है कि मामले का कच्चा मान स्वयं स्ट्रिंग प्रारूप में है। इसे आजमाइए।

enum City: String {
  case Melbourne, Chelyabinsk, Bursa
}

let city = City.Melbourne.rawValue

// city is "Melbourne"

3

स्विफ्ट के लिए:

extension UIDeviceBatteryState: CustomStringConvertible {

    public var description: String {
        switch self {
        case .unknown:
            return "unknown"
        case .unplugged:
            return "unplugged"
        case .charging:
            return "charging"
        case .full:
            return "full"
        }
    }

}

अगर आपका वैरिएबल "BatteryState" है तो कॉल करें:

self.batteryState.description

1

सरल लेकिन काम करता है ...

enum ViewType : Int {
    case    Title
    case    Buttons
    case    View
}

func printEnumValue(enum: ViewType) {

    switch enum {
    case .Title: println("ViewType.Title")
    case .Buttons: println("ViewType.Buttons")
    case .View: println("ViewType.View")
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.