some View
है एक अपारदर्शी परिणाम प्रकार के रूप में द्वारा शुरू एसई 0244 और Xcode 11. आप के साथ स्विफ्ट 5.1 में उपलब्ध है एक "रिवर्स" जेनेरिक प्लेसहॉल्डर होने के रूप में इस के बारे में सोच सकते हैं।
एक सामान्य जेनेरिक प्लेसहोल्डर के विपरीत जो कॉलर द्वारा संतुष्ट है:
protocol P {}
struct S1 : P {}
struct S2 : P {}
func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.
एक अपारदर्शी परिणाम प्रकार एक अंतर्निहित जेनेरिक प्लेसहोल्डर है जो कार्यान्वयन से संतुष्ट है , इसलिए आप इस बारे में सोच सकते हैं:
func bar() -> some P {
return S1() // Implementation chooses S1 for the opaque result.
}
जैसा दिख रहा है:
func bar() -> <Output : P> Output {
return S1() // Implementation chooses Output == S1.
}
वास्तव में, इस सुविधा के साथ अंतिम लक्ष्य यह है कि इस तरह के अधिक स्पष्ट रूप में रिवर्स जेनेरिक की अनुमति दी जाए, जो आपको बाधाओं को भी जोड़ने देगा, जैसे -> <T : Collection> T where T.Element == Int
। अधिक जानकारी के लिए इस पोस्ट को देखें ।
इस से दूर करने के लिए मुख्य बात यह है कि लौटने वाला एक फ़ंक्शन वह some P
है जो एक विशिष्ट एकल कंक्रीट प्रकार का मूल्य देता है जो इसके अनुरूप होता है P
। फ़ंक्शन के भीतर विभिन्न अनुरूप प्रकारों को वापस करने का प्रयास करने से एक संकलक त्रुटि उत्पन्न होती है:
// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
if x > 10 {
return S1()
} else {
return S2()
}
}
जैसा कि निहित जेनेरिक प्लेसहोल्डर कई प्रकारों से संतुष्ट नहीं हो सकता है।
यह एक फ़ंक्शन रिटर्निंग के विपरीत है P
, जिसका उपयोग दोनों का प्रतिनिधित्व करने के लिए किया जा सकता है S1
और S2
क्योंकि यह एक मनमाना P
अनुरूपता मूल्य का प्रतिनिधित्व करता है :
func baz(_ x: Int) -> P {
if x > 10 {
return S1()
} else {
return S2()
}
}
ठीक है, इसलिए अपारदर्शी परिणाम प्रकारों के -> some P
प्रोटोकॉल रिटर्न प्रकारों के क्या लाभ हैं-> P
?
1. पीएटी के साथ अपारदर्शी परिणाम प्रकार का उपयोग किया जा सकता है
प्रोटोकॉल की एक प्रमुख वर्तमान सीमा यह है कि PATs (संबद्ध प्रकार के प्रोटोकॉल) को वास्तविक प्रकारों के रूप में उपयोग नहीं किया जा सकता है। यद्यपि यह एक प्रतिबंध है जो संभवतः भाषा के भविष्य के संस्करण में उठा लिया जाएगा, क्योंकि अपारदर्शी परिणाम प्रकार प्रभावी रूप से सिर्फ सामान्य प्लेसहोल्डर हैं, उन्हें आज PAT के साथ उपयोग किया जा सकता है।
इसका मतलब है कि आप इस तरह की चीजें कर सकते हैं:
func giveMeACollection() -> some Collection {
return [1, 2, 3]
}
let collection = giveMeACollection()
print(collection.count) // 3
2. अपारदर्शी परिणाम प्रकारों की पहचान होती है
क्योंकि अपारदर्शी परिणाम प्रकार एक एकल कंक्रीट प्रकार को लागू करता है, इसलिए संकलक जानता है कि एक ही फ़ंक्शन के दो कॉल को एक ही प्रकार के दो मान वापस करने होंगे।
इसका मतलब है कि आप इस तरह की चीजें कर सकते हैं:
// foo() -> <Output : Equatable> Output {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.
यह कानूनी है क्योंकि कंपाइलर जानता है कि दोनों x
और y
एक ही ठोस प्रकार है। यह एक महत्वपूर्ण आवश्यकता है ==
, जहां दोनों प्रकार के पैरामीटर Self
।
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
इसका मतलब यह है कि यह दो मूल्यों की अपेक्षा करता है जो दोनों एक ही प्रकार के ठोस अनुरूप प्रकार हैं। यहां तक कि अगर Equatable
एक प्रकार के रूप में उपयोग करने योग्य थे, तो आप Equatable
एक दूसरे के साथ दो मनमाने ढंग से मूल्यों की तुलना करने में सक्षम नहीं होंगे , उदाहरण के लिए:
func foo(_ x: Int) -> Equatable { // Assume this is legal.
if x > 10 {
return 0
} else {
return "hello world"
}
}
let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.
जैसा कि संकलक यह साबित नहीं कर सकता कि दो मनमाने Equatable
मूल्यों में एक ही अंतर्निहित ठोस प्रकार है।
इसी तरह से, अगर हमने एक और अपारदर्शी प्रकार की वापसी समारोह पेश किया:
// foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
// bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable {
return "" // The opaque result type is inferred to be String.
}
let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.
उदाहरण अवैध हो जाता है , हालांकि दोनों foo
और bar
वापस some Equatable
, उनके "रिवर्स" जेनेरिक प्लेसहोल्डर्स Output1
और Output2
विभिन्न प्रकारों से संतुष्ट हो सकते हैं।
3. अपारदर्शी परिणाम प्रकार जेनेरिक प्लेसहोल्डर्स के साथ रचना करते हैं
नियमित प्रोटोकॉल-टाइप किए गए मूल्यों के विपरीत, अपारदर्शी परिणाम प्रकार नियमित जेनेरिक प्लेसहोल्डर्स के साथ अच्छी तरह से रचना करते हैं, उदाहरण के लिए:
protocol P {
var i: Int { get }
}
struct S : P {
var i: Int
}
func makeP() -> some P { // Opaque result type inferred to be S.
return S(i: .random(in: 0 ..< 10))
}
func bar<T : P>(_ x: T, _ y: T) -> T {
return x.i < y.i ? x : y
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.
यह अगर काम नहीं किया होता makeP
तो बस लौटा था P
, दो के रूप में P
मान भिन्न अंतर्निहित ठोस प्रकार, उदाहरण के लिए हो सकता है:
struct T : P {
var i: Int
}
func makeP() -> P {
if .random() { // 50:50 chance of picking each branch.
return S(i: 0)
} else {
return T(i: 1)
}
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.
कंक्रीट प्रकार पर एक अपारदर्शी परिणाम प्रकार का उपयोग क्यों करें?
इस बिंदु पर आप अपने आप को सोच रहे होंगे कि क्यों न केवल कोड लिखें:
func makeP() -> S {
return S(i: 0)
}
ठीक है, एक अपारदर्शी परिणाम प्रकार का उपयोग आपको S
केवल प्रदान किए गए इंटरफ़ेस को उजागर करके प्रकार को एक कार्यान्वयन विवरण बनाने की अनुमति देता हैP
, जिससे आपको किसी भी कोड को तोड़ने के बिना बाद में लाइन के नीचे कंक्रीट प्रकार को बदलने का लचीलापन मिलता है जो फ़ंक्शन पर निर्भर करता है।
उदाहरण के लिए, आप प्रतिस्थापित कर सकते हैं:
func makeP() -> some P {
return S(i: 0)
}
साथ में:
func makeP() -> some P {
return T(i: 1)
}
किसी भी कोड को तोड़ने के बिना जो कॉल करता है makeP()
।
देखें अपारदर्शी प्रकार अनुभाग भाषा गाइड की और स्विफ्ट विकास प्रस्ताव इस सुविधा पर अधिक जानकारी के लिए।