2015-07-31 11 views
14

कैसे struct क्षेत्रों उत्परिवर्तित के बारे में Rust book से:समझना struct मैदान उत्परिवर्तन

let mut point = Point { x: 0, y: 0 }; 
point.x = 5; 

और बाद में:

अस्थिरता संरचना के ही नहीं, बंधन की संपत्ति है।

यह मेरे लिए जवाबी सहज लगता है क्योंकि point.x = 5 जैसे मैं चर point rebinding कर रहा हूँ नहीं लगती है। क्या यह समझाने का कोई तरीका है तो यह अधिक सहज है?

एक ही रास्ता मैं अपने सिर लपेट कर सकते हैं चारों ओर इस "कल्पना" है कि मैं एक अलग x मूल्य के साथ मूल Point की एक प्रति के लिए point rebinding कर रहा हूँ है (यहां तक ​​कि यकीन नहीं है कि सही है)।

उत्तर

5

मुझे एक ही भ्रम था। मेरे लिए यह दो अलग गलतफहमी से आया था। सबसे पहले, मैं एक ऐसी भाषा से आया जहां चर (उर्फ बाइंडिंग) मूल्यों के लिए स्पष्ट रूप से संदर्भ थे। उस भाषा में संदर्भ को म्यूट करने और उस मूल्य को म्यूट करने के बीच अंतर करना महत्वपूर्ण था जिसे संदर्भित किया गया था। दूसरा, मैंने "संरचना स्वयं" द्वारा सोचा था कि पुस्तक तत्काल मूल्य का जिक्र कर रही थी, लेकिन "संरचना" द्वारा इसका अर्थ विनिर्देश/घोषणा है, उस प्रकार का एक विशेष मूल्य नहीं।

जंग में चर अलग हैं।reference से:

एक चर एक ढेर फ्रेम का एक घटक ...

एक स्थानीय चर (या स्टैक-स्थानीय आवंटन) सीधे, ढेर की स्मृति के भीतर आवंटित एक मूल्य रखती है। मान स्टैक फ्रेम का हिस्सा है। स्मृति का एक हिस्सा - -

तो एक चर एक ढेर फ्रेम का एक घटक है कि सीधे मूल्य रखती है। मूल्य से अलग होने का कोई संदर्भ नहीं है, उत्परिवर्तन का कोई संदर्भ नहीं है। परिवर्तनीय और मान स्मृति का एक ही हिस्सा हैं।

एक परिणाम यह है कि स्मृति के एक अलग हंक को संदर्भित करने के लिए इसे बदलने की भावना में एक चर को पुन: संयोजित करना जंग के स्मृति मॉडल के साथ संगत नहीं है। (एनबी let x = 1; let x = 2; दो चर बनाता है।)

तो पुस्तक यह इंगित कर रही है कि एक संरचना की परिभाषा के भाग के बजाय "स्मृति के प्रति हंक" स्तर पर उत्परिवर्तन घोषित किया गया है।

एक ही रास्ता मैं अपने सिर लपेट कर सकते हैं चारों ओर इस "कल्पना" है कि मैं एक अलग एक्स मूल्य के साथ मूल प्वाइंट की एक प्रति के लिए rebinding बिंदु हूँ है (भी नहीं लगता है कि सही है)

इसके बजाय कल्पना करें कि आप 0 में से किसी एक को स्मृति के एक हंक में बदल रहे हैं; और वह मान point द्वारा निर्दिष्ट स्मृति के भीतर रहता है। "बाइंडिंग म्यूटेबल है" का अर्थ यह है कि आप बाइंडिंग द्वारा निर्दिष्ट स्मृति के हंक को बदल सकते हैं, जिसमें इसका केवल एक हिस्सा म्यूट करना शामिल है, उदा। एक संरचना क्षेत्र स्थापित करके। जंग के भीतर अभिव्यक्ति के रूप में वर्णित तरीके से जंग के चर को पुन: संयोजित करने के बारे में सोचें।

+0

आपने मुझे सही रास्ते पर सेट किया है मुझे इसे क्रिया में देखने के लिए एक डेमो लिखना होगा (मेरा जवाब देखें) – Kelvin

+0

@ केल्विन अपने डेमो पोस्ट करने के लिए धन्यवाद। यह डालने का एक अच्छा तरीका है। –

6

यहां "बाध्यकारी" एक क्रिया नहीं है, यह एक संज्ञा है। आप कह सकते हैं कि जंग बाइंडिंग में चर के पर्याय हैं। इसलिए, आप उस मार्ग को

उत्परिवर्तन चर की एक संपत्ति है, न कि संरचना के स्वयं।

अब, मुझे लगता है, यह स्पष्ट होना चाहिए - आप चर को परिवर्तनीय के रूप में चिह्नित करते हैं और इसलिए आप इसकी सामग्री को संशोधित कर सकते हैं।

+2

ठीक है, मुझे लगता है कि थोड़ा सा मदद करता है। तो ऐसा लगता है कि एक चर के सामने 'mut' बस परिवर्तनीय * गुण * को चर पर लागू करता है। और वह संपत्ति कुछ चीजों का तात्पर्य है, उदा। रिबाइंडिंग, और स्ट्रक्चर-फील्ड संशोधन। क्या यह सही है? – Kelvin

+0

हां, आप अधिकतर सही हैं (सिवाय इसके कि 'म्यूट' इस अर्थ में पुन: बाध्यकारी को प्रभावित नहीं करता है कि आप अभी भी 'x = 10 चलिए लिख सकते हैं; x = 12' दें, भले ही' x' 'mut' नहीं है। ' म्यूट 'वास्तव में मूल्य में असाइनमेंट की अनुमति देता है (या तो वैरिएबल स्वयं या उसके अंदर एक फ़ील्ड यदि यह संरचना है) और' और mut' संदर्भों को फिर से, मान या उपफील्ड में ले जा रहा है। –

10

यह मेरे लिए उलझन में प्रतीत होता है क्योंकि point.x = 5 ऐसा नहीं लगता है कि मैं चर बिंदु को पुनर्निर्मित कर रहा हूं। क्या यह समझाने का कोई तरीका है तो यह अधिक सहज है? , बयान चर के (बंधन) के रूप में प्रकार या किसी विशिष्ट क्षेत्र की एक संपत्ति होने का विरोध -

यह सब कह रही है कि क्या है या नहीं कुछ परिवर्तनशील है let द्वारा निर्धारित किया जाता है।

उदाहरण में, point और उसके खेतों परिवर्तनशील क्योंकि point एक let mut बयान में (के रूप में एक सरल let बयान के खिलाफ) तथा सामान्यतः Point प्रकार के कुछ संपत्ति की वजह से शुरू की है कर रहे हैं।

एक विपरीत के रूप में, दिखाने के लिए क्यों यह दिलचस्प है:

type point = 
    { x: int; 
    mutable y: int; 
    }; 

इसका मतलब यह है कि आप y उत्परिवर्तित कर सकते हैं: अन्य भाषाओं में, OCaml तरह, आप प्रकार की परिभाषा में परिवर्तनशील कुछ फ़ील्ड चिह्नित कर सकते हैं प्रत्येक point मान का क्षेत्र, लेकिन आप कभी भी x को म्यूटेट नहीं कर सकते हैं।

4

@ एम-एन के उत्तर ने मुझे सही रास्ते पर सेट किया। यह सब ढेर पते के बारे में है! यहां एक प्रदर्शन है जो मेरे दिमाग में दृढ़ हो गया है जो वास्तव में हो रहा है। इन कर रहे हैं

== clobber binding 
val=1 | addr=0x7fff6112863c 
val=2 | addr=0x7fff6112858c 
== reassign 
val=1 | addr=0x7fff6112847c 
val=2 | addr=0x7fff6112847c 
== Struct: clobber binding 
xval,yval=(1, 2) | pointaddr=0x7fff611282b8, xaddr=0x7fff611282b8, yaddr=0x7fff611282c0 
xval,yval=(3, 4) | pointaddr=0x7fff61128178, xaddr=0x7fff61128178, yaddr=0x7fff61128180 
== Struct: reassign 
xval,yval=(1, 2) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0 
    (entire struct) 
xval,yval=(3, 4) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0 
    (individual members) 
xval,yval=(5, 6) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0 

प्रमुख बिंदु::

  • उपयोग let "पीटना" के लिए एक मौजूदा बंधन (नए स्टैक पता

    struct Point { 
        x: i64, 
        y: i64, 
    } 
    
    fn main() { 
        { 
         println!("== clobber binding"); 
         let a = 1; 
         println!("val={} | addr={:p}", a, &a); 
         // This is completely new variable, with a different stack address 
         let a = 2; 
         println!("val={} | addr={:p}", a, &a); 
        } 
        { 
         println!("== reassign"); 
         let mut b = 1; 
         println!("val={} | addr={:p}", b, &b); 
         // uses same stack address 
         b = 2; 
         println!("val={} | addr={:p}", b, &b); 
        } 
        { 
         println!("== Struct: clobber binding"); 
         let p1 = Point{ x: 1, y: 2 }; 
         println!(
          "xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}", 
          p1.x, p1.y,   &p1,   &p1.x,  &p1.y); 
    
         let p1 = Point{ x: 3, y: 4 }; 
         println!(
          "xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}", 
          p1.x, p1.y,   &p1,   &p1.x,  &p1.y); 
        } 
        { 
         println!("== Struct: reassign"); 
         let mut p1 = Point{ x: 1, y: 2 }; 
         println!(
          "xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}", 
          p1.x, p1.y,   &p1,   &p1.x,  &p1.y); 
    
         // each of these use the same addresses; no new addresses 
         println!(" (entire struct)"); 
         p1 = Point{ x: 3, y: 4 }; 
         println!(
          "xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}", 
          p1.x, p1.y,   &p1,   &p1.x,  &p1.y); 
    
         println!(" (individual members)"); 
         p1.x = 5; p1.y = 6; 
         println!(
          "xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}", 
          p1.x, p1.y,   &p1,   &p1.x,  &p1.y); 
        } 
    } 
    

    आउटपुट (पते स्पष्ट रूप से चलाने के प्रति थोड़े अलग हैं))। यह तब भी होता है जब चर को घोषित किया गया था, इसलिए सावधान रहें।

  • मौजूदा स्टैक पते का पुन: उपयोग करने के लिए mut का उपयोग करें, लेकिन पुन: असाइन करते समय let का उपयोग न करें।

    • आप एक पूरे परिवर्तनशील struct पुन: असाइन करते हैं, तो यह व्यक्तिगत रूप से प्रत्येक सदस्य बताए के बराबर है:

    यह परीक्षण दिलचस्प बातें की एक जोड़ी का पता चलता है।

  • संरचना धारण करने वाले परिवर्तनीय का पता पहले सदस्य के पते जैसा ही है। मुझे लगता है कि अगर आप सी/सी ++ पृष्ठभूमि से आ रहे हैं तो यह समझ में आता है।
संबंधित मुद्दे