परिचय: Copy और Clone एक जैसे क्यों नहीं हैं?
\n\nRust सीखने वाला हर व्यक्ति देर-सबेर दो रहस्यमयी ट्रेट्स से टकराता है: Copy और Clone। पहली नज़र में ये एक ही काम करते हैं - वैल्यू की डुप्लीकेट बनाना। लेकिन असली फर्क बारीकियों में छिपा है।
सोचिए, आप एक प्रोग्राम लिख रहे हैं और एक वैल्यू को फंक्शन में भेज रहे हैं। C++ में यह कॉपी होता (या मूव, अगर किस्मत अच्छी हो)। Python में - बस ऑब्जेक्ट का एक और रेफरेंस। लेकिन Rust में... Rust आपको स्पष्ट रूप से तय करने पर मजबूर करता है: "मैं चाहता हूँ कि यह वैल्यू कॉपी हो" या "मैं इसे क्लोन करना चाहता हूँ, लागत के बारे में जानते हुए"।
\n\nयहीं पर Copy और Clone के बीच की रेखा खिंचती है। पहला है "बिट-दर-बिट हल्की कॉपी"। दूसरा है "जानबूझकर, संभवतः महँगी डुप्लीकेशन"।
आइए उदाहरणों के साथ समझते हैं कि कब और क्या उपयोग करें, ताकि आपका Rust कोड न सिर्फ सही हो, बल्कि कुशल भी हो।
\n\nमुख्य बात: Copy बनाम Clone
\n\nClone क्या है?
\n\nClone एक ट्रेट है जो आपको .clone() मेथड देता है। इसे कॉल करके आप कंपाइलर को स्पष्ट रूप से बताते हैं: "मुझे पता है यह महँगा हो सकता है, लेकिन मुझे एक स्वतंत्र कॉपी चाहिए"।
Clone की विशेषताएँ:
- \n
- किसी भी टाइप के लिए इम्प्लीमेंट किया जा सकता है \n
.clone()को स्पष्ट रूप से कॉल करना ज़रूरी है \n - डीप कॉपी कर सकता है (जैसे
VecयाStringके लिए) \n - ओनरशिप सीमेंटिक्स नहीं बदलता - क्लोन करने के बाद आपके पास दो स्वतंत्र वैल्यू होती हैं \n
Copy क्या है?
\n\nCopy एक "मार्कर" ट्रेट है (बिना किसी मेथड के)। अगर कोई टाइप Copy इम्प्लीमेंट करता है, तो कंपाइलर असाइनमेंट या फंक्शन कॉल के दौरान उसके बिट्स को कॉपी कर सकता है। इसके लिए .clone() कॉल करने की ज़रूरत नहीं है।
Copy की विशेषताएँ:
- \n
- केवल सरल टाइप्स के लिए काम करता है जिन्हें सुरक्षित रूप से बिटवाइज़ कॉपी किया जा सके \n
- स्पष्ट कॉल की ज़रूरत नहीं - कॉपी अपने आप होती है \n
- टाइप को अभी भी
Cloneइम्प्लीमेंट करना होगा (यह सुपरट्रेट है) \n - कॉपी करने के बाद मूल वैल्यू वैध बनी रहती है \n
व्यावहारिक उदाहरण: कोड में यह कैसे काम करता है
\n\nउदाहरण 1: बेसिक टाइप्स (Copy)
\n\nपूर्णांक, फ्लोटिंग-पॉइंट नंबर, बूलियन वैल्यू - ये सभी Copy इम्प्लीमेंट करते हैं:
fn main() {\n let x = 42;\n let y = x; // x को y में कॉपी किया गया, x अभी भी उपलब्ध है\n \n println!("x = {}, y = {}", x, y); // काम करता है!\n}\n\nयहाँ x एक i32 है, जो Copy इम्प्लीमेंट करता है। इसलिए y = x असाइनमेंट पर कॉपी होती है, और x वैध रहता है।
उदाहरण 2: String (केवल Clone)
\n\nलेकिन String एक जटिल टाइप है जो हीप में डेटा स्टोर करता है। यह Clone इम्प्लीमेंट करता है, लेकिन Copy नहीं:
fn main() {\n let s1 = String::from("नमस्ते, Rust!");\n let s2 = s1; // s1, s2 में मूव हो जाता है\n \n // println!("{}", s1); // त्रुटि! s1 के पास अब डेटा नहीं है\n \n let s3 = s2.clone(); // इस तरह स्पष्ट क्लोनिंग संभव है\n println!("s2 = {}, s3 = {}", s2, s3); // काम करता है!\n}\n\nString Copy क्यों नहीं हो सकता? क्योंकि String की बिटवाइज़ कॉपी करने से हीप में एक ही मेमोरी के दो पॉइंटर बन जाएँगे। दोनों के ड्रॉप होने पर - डबल मेमोरी फ्री होगी। Clone एक पूरी तरह से स्वतंत्र कॉपी बनाता है।
उदाहरण 3: अपना खुद का Copy टाइप
\n\nआप अपने टाइप को Copy बना सकते हैं, अगर वह केवल Copy टाइप्स से बना हो:
#[derive(Debug, Copy, Clone)]\nstruct Point {\n x: f64,\n y: f64,\n}\n\nfn main() {\n let p1 = Point { x: 1.0, y: 2.0 };\n let p2 = p1; // कॉपी होता है, p1 बना रहता है\n \n println!