स्विफ्ट स्विच स्टेटमेंट की तुलना में कम या अधिक


145

मैं switchस्विफ्ट में बयानों से परिचित हूं , लेकिन सोच रहा हूं कि कोड के इस टुकड़े को कैसे प्रतिस्थापित किया जाए switch:

if someVar < 0 {
    // do something
} else if someVar == 0 {
    // do something else
} else if someVar > 0 {
    // etc
}

हालांकि यह एक दिलचस्प सवाल है, मुझे लगता है कि स्विच का उपयोग करने वाला कोड, यदि कथनों की तुलना में बहुत कम पठनीय है। सिर्फ इसलिए कि आप कर सकते हैं, इसका मतलब यह नहीं है कि आपको चाहिए।
रोज

जवाबों:


241

यहाँ एक दृष्टिकोण है। मान someVarलेना एक Intया अन्य है Comparable, आप वैकल्पिक रूप से ऑपरेंड को एक नए चर में असाइन कर सकते हैं। इससे आप whereकीवर्ड का उपयोग कर सकते हैं लेकिन आप इसे स्कोप कर सकते हैं :

var someVar = 3

switch someVar {
case let x where x < 0:
    print("x is \(x)")
case let x where x == 0:
    print("x is \(x)")
case let x where x > 0:
    print("x is \(x)")
default:
    print("this is impossible")
}

इसे थोड़ा सरल बनाया जा सकता है:

switch someVar {
case _ where someVar < 0:
    print("someVar is \(someVar)")
case 0:
    print("someVar is 0")
case _ where someVar > 0:
    print("someVar is \(someVar)")
default:
    print("this is impossible")
}

आप whereश्रेणी मिलान के साथ पूरी तरह से कीवर्ड से बच सकते हैं :

switch someVar {
case Int.min..<0:
    print("someVar is \(someVar)")
case 0:
    print("someVar is 0")
default:
    print("someVar is \(someVar)")
}

9
मैं default: fatalError()संभावित तर्क त्रुटियों का जल्द पता लगाने की सलाह देता हूं ।
मार्टिन आर।

1
धन्यवाद! ये उदाहरण बहुत मददगार हैं और वे मेरे मुद्दे को हल करते हैं! (अन्य उदाहरण भी अच्छे थे, लेकिन आपके लिए मेरे लिए सबसे ज्यादा मददगार थे)
पीटर

1
@MartinR assertionFailureएक सुरक्षित विकल्प लगता है, खासकर जब एक टीम में काम कर रहा हो।
माइकल वोलिन

119

स्विफ्ट 5 के साथ, आप अपने स्टेटमेंट को बदलने के लिए निम्न स्विच में से एक चुन सकते हैं।


# 1 स्विच के साथ PartialRangeFromऔर का उपयोग करनाPartialRangeUpTo

let value = 1

switch value {
case 1...:
    print("greater than zero")
case 0:
    print("zero")
case ..<0:
    print("less than zero")
default:
    fatalError()
}

# 2 स्विच के साथ ClosedRangeऔर का उपयोग करनाRange

let value = 1

switch value {
case 1 ... Int.max:
    print("greater than zero")
case Int.min ..< 0:
    print("less than zero")
case 0:
    print("zero")
default:
    fatalError()
}

# 3 जहां क्लॉज के साथ स्विच का उपयोग करना

let value = 1

switch value {
case let val where val > 0:
    print("\(val) is greater than zero")
case let val where val == 0:
    print("\(val) is zero")
case let val where val < 0:
    print("\(val) is less than zero")
default:
    fatalError()
}

# 4 जहां क्लॉज और असाइनमेंट के साथ स्विच का उपयोग करना _

let value = 1

switch value {
case _ where value > 0:
    print("greater than zero")
case _ where value == 0:
    print("zero")
case _ where value < 0:
    print("less than zero")
default:
    fatalError()
}

# 5 RangeExpressionप्रोटोकॉल के ~=(_:_:)ऑपरेटर के साथ स्विच का उपयोग करना

let value = 1

switch true {
case 1... ~= value:
    print("greater than zero")
case ..<0 ~= value:
    print("less than zero")
default:
    print("zero")
}

# 6 Equatableप्रोटोकॉल के ~=(_:_:)ऑपरेटर के साथ स्विच का उपयोग करना

let value = 1

switch true {
case value > 0:
    print("greater than zero")
case value < 0:
    print("less than zero")
case 0 ~= value:
    print("zero")
default:
    fatalError()
}

# 7 स्विच का उपयोग करना PartialRangeFrom, PartialRangeUpToऔरRangeExpression की contains(_:)विधि

let value = 1

switch true {
case (1...).contains(value):
    print("greater than zero")
case (..<0).contains(value):
    print("less than zero")
default:
    print("zero")
}

1
# 2 में चूक मामले की आवश्यकता क्यों है? परतदार लगता है कि अगर रैन्ज Int.min से Int.max तक है तो क्या बचा है?
--ολ17ν.λαβέ

वाह, विकल्पों की अच्छी सूची। यह जानने के लिए अच्छा है कि ऐसा करने के कई तरीके हैं।
क्रिस्टोफर पिक्सले

2
अच्छा अवलोकन लेकिन त्रुटिपूर्ण है क्योंकि 0 और 1 के बीच की संख्या बेहिसाब है। 0.1एक घातक त्रुटि को फेंकता है क्योंकि 1...केवल 1 से संख्याएँ शामिल होती हैं। इसलिए यह समाधान केवल तभी काम करता है जब valueवह एक Intखतरनाक हो, क्योंकि यदि चर प्रकार बदलता है तो कार्यक्षमता बिना किसी संकलक त्रुटि के टूट जाती है।
मैनुएल

1
आपका समाधान डबल प्रकार के लिए सही तरीके से काम नहीं करता है। केस 1 ...: प्रिंट ("शून्य से अधिक") 0 से अधिक नहीं है यह अधिक से अधिक या 1 के बराबर है।
व्लाद

20

switchबयान, हुड के नीचे, का उपयोग करता है ~=ऑपरेटर। तो यह:

let x = 2

switch x {
case 1: print(1)
case 2: print(2)
case 3..<5: print(3..<5)
default: break
}

इसका वर्णन करता है:

if 1          ~= x { print(1) }
else if 2     ~= x { print(2) }
else if 3..<5 ~= x { print(3..<5) }
else {  }

यदि आप मानक पुस्तकालय संदर्भ को देखते हैं, तो यह आपको बता सकता है कि ~=ऐसा करने के लिए अतिभारित क्या है : इसमें शामिल है श्रेणी-मिलान, और समतुल्य चीजों के लिए समीकरण। (शामिल नहीं है एनुम-केस मिलान, जो भाषा की विशेषता है, बजाय एसटीडी के एक फ़ंक्शन के लिबास में)

आप देखेंगे कि यह बायीं ओर सीधे बूलियन से मेल नहीं खाता है। उन प्रकार की तुलनाओं के लिए, आपको एक कथन जोड़ना होगा।

जब तक ... आप ~=ऑपरेटर को खुद को अधिभारित नहीं करते हैं । (यह आमतौर पर अनुशंसित नहीं है ) एक संभावना कुछ इस तरह होगी:

func ~= <T> (lhs: T -> Bool, rhs: T) -> Bool {
  return lhs(rhs)
}

इसलिए यह एक ऐसे फ़ंक्शन से मेल खाता है जो दाईं ओर अपने पैरामीटर पर बाईं ओर एक बूलियन देता है। यहाँ आप के लिए इसका इस्तेमाल कर सकते कुछ ऐसी बातें है:

func isEven(n: Int) -> Bool { return n % 2 == 0 }

switch 2 {
case isEven: print("Even!")
default:     print("Odd!")
}

आपके मामले के लिए, आपके पास एक बयान हो सकता है जो इस तरह दिखता है:

switch someVar {
case isNegative: ...
case 0: ...
case isPositive: ...
}

लेकिन अब आपको नया isNegativeऔर परिभाषित करना हैisPositive कार्यों करना होगा। जब तक आप कुछ और ऑपरेटरों को ओवरलोड ...

आप सामान्य प्रीफ़िक्स ऑपरेटरों को ओवरलोड कर सकते हैं जो कि उपसर्ग या उपसर्ग ऑपरेटर के रूप में हो सकते हैं। यहाँ एक उदाहरण है:

postfix operator < {}

postfix func < <T : Comparable>(lhs: T)(_ rhs: T) -> Bool {
  return lhs < rhs
}

यह इस तरह काम करेगा:

let isGreaterThanFive = 5<

isGreaterThanFive(6) // true
isGreaterThanFive(5) // false

कम्बाइन पहले समारोह के साथ कि, और अपने स्विच बयान इस तरह दिखेगा कर सकते हैं:

switch someVar {
case 0< : print("Bigger than 0")
case 0  : print("0")
default : print("Less than 0")
}

अब, आपको शायद इस तरह की चीज़ का प्रयोग व्यवहार में नहीं करना चाहिए: यह थोड़ा नीरस है। आप (शायद) whereबयान के साथ चिपके हुए बेहतर हैं । उस ने कहा, के स्विच स्टेटमेंट पैटर्न

switch x {
case negative:
case 0:
case positive:
}

या

switch x {
case lessThan(someNumber):
case someNumber:
case greaterThan(someNumber):
}

इसके लिए पर्याप्त लगता है कि यह विचार करने लायक हो।


1
आपके सवाल का जवाब कहां है? मैं इसे नहीं ढूँढ सकता।
हनी

1
स्थिति 3 .. <5: प्रिंट (3 .. <5) - सचमुच पहले पैराग्राफ में। यह उत्तर रेखांकित है। मुझे इतना कोड बचाता है।
करीम

14

आप ऐसा कर सकते हैं:

switch true {
case someVar < 0:
    print("less than zero")
case someVar == 0:
    print("eq 0")
default:
    print("otherwise")
}

6

चूँकि कोई व्यक्ति पहले ही case let x where x < 0:यहाँ पोस्ट कर चुका है, जहाँ एक विकल्प someVarहै Int

switch someVar{
case Int.min...0: // do something
case 0: // do something
default: // do something
}

और यहाँ के लिए एक विकल्प someVarहै Double:

case -(Double.infinity)...0: // do something
// etc

6

यह है कि यह श्रेणियों के साथ कैसा दिखता है

switch average {
case 0..<40: //greater or equal than 0 and less than 40
    return "T"
case 40..<55: //greater or equal than 40 and less than 55
    return "D"
case 55..<70: //greater or equal than 55 and less than 70
    return "P"
case 70..<80: //greater or equal than 70 and less than 80
    return "A"
case 80..<90: //greater or equal than 80 and less than 90
    return "E"
case 90...100: //greater or equal than 90 and less or equal than 100
    return "O"
default:
    return "Z"
}

3

<0अभिव्यक्ति (अब और?) काम नहीं करता तो मैं इस के साथ समाप्त हो गया:

स्विफ्ट 3.0:

switch someVar {
    case 0:
        // it's zero
    case 0 ..< .greatestFiniteMagnitude:
        // it's greater than zero
    default:
        // it's less than zero
    }

1
स्विफ्ट 3.0 में, X_MAXने ले लिया है .greatestFiniteMagnitude, यानी Double.greatestFiniteMagnitude, CGFloat.greatestFiniteMagnitudeआदि तो आम तौर पर, आप बस कर सकते हैं case 0..< .greatestFiniteMagnitudeके प्रकार के बाद से someVarपहले से ही जाना जाता है
Guig

@ डोरियन रॉय ऑपरेटर को मान्यता var timeLeft = 100 switch timeLeft {case 0...<=7200: print("ok") default:print("nothing") }क्यों <=नहीं दी जाती है? अगर मैं इसके बिना बारे में यह काम करता है के बराबर। धन्यवाद
bibscy

@bibcy आप बंद रेंज ऑपरेटर का उपयोग करना चाहते हैं: case 0...7200:ऑपरेटर <=एक तुलना ऑपरेटर है। एक स्विच में आप केवल रेंज ऑपरेटर्स (डॉक्स देखें)
डोरियन रॉय

यह महान था। मुझे यह त्रुटि प्रकार का पैटर्न मिल रहा था 'रेंज <डबल>' टाइप '' इंट '' के मूल्यों से मेल नहीं खा सकता है क्योंकि मेरा someVarएक था Intऔर मुझे कुछ करना था Double() `इसे काम करने के लिए ...
हनी

2

खुशी है कि स्विफ्ट 4 समस्या का समाधान करती है:

3 में एक समाधान के रूप में मैंने किया:

switch translation.x  {
case  0..<200:
    print(translation.x, slideLimit)
case  -200..<0:
    print(translation.x, slideLimit)
default:
    break
}

काम करता है, लेकिन नहीं आदर्श

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