सामान्य पैरामीटर 'T' असाइनमेंट के बाद अनुमान नहीं लगाया जा सकता है

Aug 18 2020
// 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प्रकार कैसे होता है, इस पर कोई असर नहीं होना चाहिए , लेकिन स्पष्ट रूप से यह होता है।

क्या कोई ऐसा होने पर कुछ प्रकाश डाल सकता है, और इसे सही करने के लिए क्या (यदि कुछ भी) किया जा सकता है?

जवाब

2 Sweeper Aug 18 2020 at 11:45

यह कंपाइलर बग हो सकता है या नहीं भी हो सकता है।

यह ज्ञात है कि स्विफ्ट कुछ बंद किया जाना, अर्थात्, बहु बयान लोगों के प्रकार अनुमान लगाने के लिए कोशिश नहीं करता है, के रूप में एसआर 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
2 Malik Aug 18 2020 at 11:44

फ़ंक्शन fएक फ़ंक्शन में एक पैरामीटर के रूप में लेता है जो बदले में प्रकार का पैरामीटर लेता है Tऔर कुछ भी नहीं लौटाता है ( Void)। बंद प्रकार के स्वचालित रूप से बंद करने के लिए, इसमें एकल (और कभी-कभी सरल) अभिव्यक्ति शामिल होती है। कुछ भी जटिल कंपाइलर को अनुमान लगाने में मुश्किल करता है (जो कंपाइलर के दृष्टिकोण से समझ में आता है)। जाहिर है, let _ = g($0)एक जटिल बयान है जहां तक ​​संकलक का संबंध है। अधिक जानकारी के लिए, इस मेलिंग सूची चर्चा देखें

AlexanderNikolaychuk Aug 18 2020 at 11:44

ऐसा लगता है कि @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)

शायद यह यहाँ एक कुंजी है