सामान्य पैरामीटर 'T' असाइनमेंट के बाद अनुमान नहीं लगाया जा सकता है
// Xcode 11.6 / Swift 5
import Foundation
func f<T>(_: (T) -> Void) { }
@discardableResult
func g(_: Int) -> Int { 0 }
f { g($0) } // compiles fine f { let _ = g($0) } // Generic parameter 'T' could not be inferred
उपरोक्त कोड में, जेनेरिक फ़ंक्शन f
अपने तर्क के रूप में एक फ़ंक्शन की अपेक्षा करता है जो एक प्रकार का तर्क लेता है T
।
फ़ंक्शन g
प्रकार का एक तर्क लेता है Int
।
जब मैं लिखता हूं f { g($0) }
, तो कोड संकलन करता है। मुझे विश्वास है (कृपया मुझे सही करें अगर मैं गलत हूं) तो यह संकलन करता है क्योंकि संकलक यह अनुमान लगा सकता है कि T
यह तर्क प्रकार Int
पर आधारित है g
।
हालांकि, जब मैं लाइन g
में वापसी के मूल्य के साथ कुछ करने की कोशिश करता हूं , उदाहरण के लिए let _ = g($0)
लाइन में, कंपाइलर शिकायत करता है कि यह अब टाइप नहीं कर सकता है T
।
यह मुझे लगता है g
कि संकलक का T
प्रकार कैसे होता है, इस पर कोई असर नहीं होना चाहिए , लेकिन स्पष्ट रूप से यह होता है।
क्या कोई ऐसा होने पर कुछ प्रकाश डाल सकता है, और इसे सही करने के लिए क्या (यदि कुछ भी) किया जा सकता है?
जवाब
यह कंपाइलर बग हो सकता है या नहीं भी हो सकता है।
यह ज्ञात है कि स्विफ्ट कुछ बंद किया जाना, अर्थात्, बहु बयान लोगों के प्रकार अनुमान लगाने के लिए कोशिश नहीं करता है, के रूप में एसआर 1570 में कहा :
यह सही व्यवहार है: स्विफ्ट मल्टी-स्टेटमेंट क्लोजर के निकायों से पैरामीटर या रिटर्न प्रकार का अनुमान नहीं लगाता है।
हालाँकि, आपके बंद होने में केवल एक कथन, एक घोषणा विशिष्ट होना शामिल है। यह संभव है, यद्यपि यह अजीब है, कि उन्होंने इसे डिजाइन किया है ताकि स्विफ्ट के प्रकारों का पता लगाने की कोशिश न करें यदि क्लोजर में एक घोषणा भी शामिल है। उदाहरण के लिए, यह संकलन भी नहीं करता है
f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations
यदि यह उप-डिजाइन थे, तो इसके पीछे तर्क हो सकता है क्योंकि एक बंद में एक भी घोषणा वैसे भी बहुत मायने नहीं रखती है। जो कुछ भी घोषित किया गया है, उसका उपयोग नहीं किया जाएगा।
लेकिन फिर, यह सिर्फ अटकलें हैं, और यह एक बग भी हो सकता है।
इसे ठीक करने के लिए, बस इसे एक घोषणा के रूप में देखें:
f { _ = g($0) } // this, without the "let", is IMO the idiomatic way to ignore the function result
या
f { g($0) } // g has @discardableResult anyway, so you don't even need the wildcard
फ़ंक्शन f
एक फ़ंक्शन में एक पैरामीटर के रूप में लेता है जो बदले में प्रकार का पैरामीटर लेता है T
और कुछ भी नहीं लौटाता है ( Void
)। बंद प्रकार के स्वचालित रूप से बंद करने के लिए, इसमें एकल (और कभी-कभी सरल) अभिव्यक्ति शामिल होती है। कुछ भी जटिल कंपाइलर को अनुमान लगाने में मुश्किल करता है (जो कंपाइलर के दृष्टिकोण से समझ में आता है)। जाहिर है, let _ = g($0)
एक जटिल बयान है जहां तक संकलक का संबंध है। अधिक जानकारी के लिए, इस मेलिंग सूची चर्चा देखें
ऐसा लगता है कि @discardableResult आपको 2 प्रकार के कार्य करने की क्षमता देता है:
g (_: Int) -> Int और g (_: Int) -> शून्य (यह तब है जब आप फ़ंक्शन के परिणाम का उपयोग नहीं करना चाहते हैं)
मुझे लगता है कि
f { g($0) }
- यहाँ आपका f एक प्रकार का अनुमान लगा सकता है क्योंकि इसमें एक ही प्रकार है
(_: (T) -> Void) and (_: (Int) -> Void)
f { let _ = g($0) }
- इस मामले में जी फ़ंक्शन का प्रकार एफ फ़ंक्शन से अलग है
(_: (T) -> Void) and (_: (Int) -> Int)
यदि आप "लेट" को हटा देंगे तो यह फिर से संकलित होगा:
f { _ = g($0) }
मुझे लगता है कि f { let _ = g($0) }
- केवल Int मान f { _ = g($0) }
लौटाएं - वापसी फ़ंक्शन (_: (Int) -> Int)
शायद यह यहाँ एक कुंजी है