मैं एक ऐसा फंक्शन बनाना चाहता हूँ, जो एक अरै (या कलेक्शन या सीक्वेंस) से आगे बढ़ेगा। फिर मैं उस फ़ंक्शन को एक सरणी, और सरणी के उलट संस्करण (लेकिन कुशलतापूर्वक: रिवर्स रखने के लिए एक नया सरणी बनाए बिना) कॉल करूंगा।
अगर मैं ऐसा करता हूं:
func doIteration(points: [CGPoint]) {
for p in points {
doSomethingWithPoint(p)
}
// I also need random access to points
doSomethingElseWithPoint(points[points.count-2]) // ignore obvious index error
}
और अगर मेरे पास यह है:
let points : [CGPoint] = whatever
मैं यह ठीक कर सकता हूँ:
doIteration(points)
लेकिन अगर मैं ऐसा करता हूं:
doIteration(points.reverse())
मुझे] ReverseRandomAccessCollection <[CGPoint]> प्रकार के मान को अपेक्षित तर्क प्रकार [_] 'में परिवर्तित नहीं किया जा सकता
अब, मैं ऐसा नहीं करना चाहता:
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
भले ही यह काम करेगा, क्योंकि यह (मुझे गलत होने पर सही करेगा) एक नया सरणी बनाता है, इसे रिवर्स रिवर्सगेमऑकॉलकॉलियन से रिवर्स करके ()।
इसलिए मुझे लगता है कि मैं कुछ प्रकार के अनुक्रम प्रकार लेने के लिए अपना doIteration फ़ंक्शन लिखना चाहता हूं, इसलिए मैं रिवर्स () के परिणाम में सीधे पारित कर सकता हूं, लेकिन ReverseRandomAccessCollection बिल्कुल भी किसी भी चीज़ के अनुरूप नहीं है। मुझे लगता है कि मुझे कुछ याद आ रहा है - यहाँ स्वीकृत पैटर्न क्या है?
2 जवाब
यदि आप अपने पैरामीटर्स के प्रकार को एक जेनेरिक में बदलते हैं, तो आपको अपनी कार्यक्षमता की आवश्यकता होनी चाहिए:
func doIteration
<C: CollectionType where C.Index: RandomAccessIndexType, C.Generator.Element == CGPoint>
(points: C) {
for p in points {
doSomethingWithPoint(p)
}
doSomethingElseWithPoint(points[points.endIndex - 2])
}
इससे भी महत्वपूर्ण बात यह है कि यह नहीं होगा क्योंकि सरणी की एक प्रति बनाई जा सकती है। यदि आप reverse()
विधि द्वारा उत्पन्न प्रकार को देखते हैं:
let points: [CGPoint] = []
let reversed = points.reverse() // ReverseRandomAccessCollection<Array<__C.CGPoint>>
doIteration(reversed)
आप देखेंगे कि यह केवल एक संरचना बनाता है जो मूल सरणी का संदर्भ देता है, रिवर्स में। (हालांकि इसमें मूल्य-प्रकार के शब्दार्थ हैं) और सही जेनेरिक बाधाओं के कारण मूल फ़ंक्शन इस नए संग्रह को स्वीकार कर सकता है।
तुम यह केर सकते हो
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
या यह
doIteration(points.reverse() as [CGPoint])
लेकिन मुझे नहीं लगता कि पदचिह्न के दृष्टिकोण से कोई वास्तविक अंतर है।
परिदृश्य 1
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
इस मामले में एक नया ऐरे जिसमें संदर्भ से CGPoint(s)
मूल सरणी में मौजूद है बनाया जाता है। यह कॉपी-ऑन-राइट तंत्र के लिए धन्यवाद जो स्विफ्ट संरचनाओं का प्रबंधन करने के लिए उपयोग किया जाता है।
तो आवंटित की गई मेमोरी निम्नलिखित है:
points.count * sizeOf (पॉइंटर)
परिदृश्य 2
दूसरी ओर आप कुछ इस तरह लिख सकते हैं
doIteration(points.reverse() as [CGPoint])
लेकिन क्या आप वास्तव में मेमोरी को बचा रहे हैं? चलो देखते हैं। एक अस्थायी चर बनाया जाता है, वह चर उपलब्ध है अंदर फ़ंक्शन का दायरा doIteration
और points
में निहित प्रत्येक तत्व के लिए वास्तव में एक पॉइंटर की आवश्यकता होती है ताकि हमारे पास फिर से हो:
points.count * sizeOf (पॉइंटर)
इसलिए मुझे लगता है कि आप 2 समाधानों में से एक को सुरक्षित रूप से चुन सकते हैं।
विचार
हमें याद रखना चाहिए कि स्विफ्ट बहुत ही स्मार्ट तरीके से संरचनाओं का प्रबंधन करता है।
जब मैं लिखता हूँ
var word = "Hello"
var anotherWord = word
पहली पंक्ति पर स्विफ्ट एक संरचना बनाएं और इसे "हैलो" मान के साथ भरें। दूसरी पंक्ति में स्विफ्ट का पता चलता है कि मूल स्ट्रिंग की एक प्रति बनाने का कोई वास्तविक कारण नहीं है इसलिए मूल मान के संदर्भ में anotherWord
के अंदर लिखते हैं।
केवल जब word
या anotherWord
संशोधित किया जाता है, तो स्विफ्ट वास्तव में मूल मूल्य की एक प्रति बनाती है।