"नेस्टेबल के रूप में उधार नहीं लिया जा सकता है क्योंकि यह एक नेस्टेड सरणी इंडेक्स में माध्य के रूप में भी उधार लिया गया है"।


16

इस मामले में त्रुटि का क्या मतलब है:

fn main() {
    let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
    v[v[1]] = 999;
}
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
 --> src/main.rs:3:7
  |
3 |     v[v[1]] = 999;
  |     --^----
  |     | |
  |     | immutable borrow occurs here
  |     mutable borrow occurs here
  |     mutable borrow later used here

मैंने पाया कि अनुक्रमण अनुगामी Indexऔर IndexMutलक्षणों के माध्यम से कार्यान्वित किया जाता है और इसके v[1]लिए वाक्यगत शर्करा है *v.index(1)। इस ज्ञान से लैस, मैंने निम्नलिखित कोड चलाने की कोशिश की:

use std::ops::{Index, IndexMut};

fn main() {
    let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
    *v.index_mut(*v.index(1)) = 999;
}

मेरे आश्चर्य करने के लिए, यह निर्दोष रूप से काम करता है! पहला स्निपेट काम क्यों नहीं करता, लेकिन दूसरा करता है? जिस तरह से मैं प्रलेखन को समझता हूं, वे समकक्ष होना चाहिए, लेकिन यह स्पष्ट रूप से ऐसा नहीं है।


2
कोड के आगमन के साथ सीखना जंग? StackOverflow में आपका स्वागत है, और महान प्रश्न के लिए धन्यवाद!
स्वेन मार्नाच

यकीनन ; ) यह करने का मेरा तीसरा वर्ष है (इससे पहले 2x हास्केल) ~>
रुस्ट को

@LucasBoucke यह मज़ेदार है, मैं आमतौर पर अपनी परियोजना के लिए जंग का उपयोग करता हूं, लेकिन मैं हास्कोल में इस एओसी को लिखता हूं। वे दोनों अपने डोमेन में महान भाषाएं हैं।
बोइथियोस

जवाबों:


16

अवरोही संस्करण आपके पास की तुलना में थोड़ा अलग है। रेखा

v[v[1]] = 999;

वास्तव में करने के लिए desugars

*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;

यह एक ही त्रुटि संदेश में परिणाम करता है, लेकिन एनोटेशन यह संकेत देता है कि क्या हो रहा है:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
 --> src/main.rs:7:48
  |
7 |     *IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
  |      ------------------- ------                ^^ immutable borrow occurs here
  |      |                   |
  |      |                   mutable borrow occurs here
  |      mutable borrow later used by call

आपके अवरोही संस्करण का महत्वपूर्ण अंतर मूल्यांकन क्रम है। किसी फ़ंक्शन कॉल के तर्कों का मूल्यांकन वास्तव में फ़ंक्शन कॉल करने से पहले सूचीबद्ध क्रम में दाएं से बाएं किया जाता है। इस मामले में इसका मतलब है कि पहले &mut vमूल्यांकन किया गया है, पारस्परिक रूप से उधार लिया गया है v। अगला, Index::index(&v, 1)मूल्यांकन किया जाना चाहिए, लेकिन यह संभव नहीं है - vपहले से ही पारस्परिक रूप से उधार लिया गया है। अंत में, कंपाइलर दिखाता है कि फंक्शन कॉल के लिए म्यूटेबल रेफरेंस की जरूरत है index_mut(), इसलिए शेयर्ड रेफरेंस का प्रयास करने पर म्यूटेबल रेफरेंस अभी भी जीवित है।

जो संस्करण वास्तव में संकलित होता है, उसका मूल्यांकन थोड़ा अलग होता है।

*v.index_mut(*v.index(1)) = 999;

सबसे पहले, विधि कॉल के लिए फ़ंक्शन तर्क को बाएं से दाएं *v.index(1)मूल्यांकन किया जाता है , अर्थात पहले मूल्यांकन किया जाता है। इसमें परिणाम usizeऔर अस्थायी साझा उधार vफिर से जारी किए जा सकते हैं। फिर, रिसीवर का index_mut()मूल्यांकन किया जाता है, अर्थात् vपारस्परिक रूप से उधार लिया जाता है। यह ठीक काम करता है, क्योंकि साझा उधार को पहले ही अंतिम रूप दिया जा चुका है, और पूरी अभिव्यक्ति उधारकर्ता को पास करती है।

ध्यान दें कि जो संस्करण केवल संकलित करता है वह "गैर-शाब्दिक जीवनकाल" की शुरुआत के बाद से करता है। रस्ट के पुराने संस्करणों में, साझा उधार अभिव्यक्ति के अंत तक जीवित रहेगा और एक समान त्रुटि के परिणामस्वरूप होगा।

मेरी राय में सबसे साफ समाधान एक अस्थायी चर का उपयोग करना है:

let i = v[1];
v[i] = 999;

ओह! यहाँ बहुत कुछ चल रहा है! समझाने के लिए समय निकालने के लिए धन्यवाद! (दिलचस्प रूप से "quirks" के प्रकार मेरे लिए एक भाषा को अधिक दिलचस्प बनाते हैं ...)। क्या आप शायद इस बात का संकेत भी दे *v.index_mut(*v.index_mut(1)) = 999;सकते हैं कि फेल होने के साथ "v को एक से अधिक बार उधार नहीं लिया जा सकता है" ~ संकलक नहीं होना चाहिए, जैसा *v.index_mut(*v.index(1)) = 999;कि यह पता लगाने में सक्षम है कि आंतरिक उधार की अब आवश्यकता नहीं है?
लुकास बुके 20

@LucasBoucke जंग में कभी-कभी थोड़ा असुविधाजनक होता है, लेकिन ज्यादातर मामलों में समाधान सरल होता है, जैसा कि इस मामले में होता है। कोड अभी भी काफी पठनीय है, जो आपके पास मूल रूप से जितना था उससे थोड़ा अलग है, इसलिए व्यवहार में यह कोई बड़ी बात नहीं है।
स्वेन मार्नाच

@LucasBoucke क्षमा करें, मैंने अब तक आपका संपादन नहीं देखा था। का परिणाम *v.index(1)है मूल्य है कि सूचकांक में संग्रहीत, और कहा कि मूल्य के उधार रखने के लिए की आवश्यकता नहीं है vजिंदा। *v.index_mut(1)दूसरी ओर, का परिणाम एक परिवर्तनशील स्थान अभिव्यक्ति है जिसे सैद्धांतिक रूप से सौंपा जा सकता है, इसलिए यह उधार को जीवित रखता है। सतह पर, यह उधार लेने वाले को सिखाने के लिए संभव होना चाहिए कि मूल्य अभिव्यक्ति के संदर्भ में एक स्थान अभिव्यक्ति को एक मूल्य अभिव्यक्ति के रूप में माना जा सकता है, इसलिए यह संभव है कि यह रस्ट के कुछ भविष्य के संस्करण में संकलित होगा।
स्वेन मार्नाच

कैसे एक RFC के बारे में यह करने के लिए:{ let index = *Index::index(&v, 1); let value = 999; *IndexMut::index_mut(&mut v, index) = value; }
Boiethios

@FrenchBoiethios मुझे पता नहीं चला है कि आप इसे कैसे औपचारिक रूप देंगे, और मुझे यकीन है कि यह उड़ान भरने के लिए कभी नहीं होगा। यदि आप इसे संबोधित करना चाहते हैं, तो मेरे द्वारा देखे जाने का एकमात्र तरीका उधारकर्ता के चेक में सुधार है, उदाहरण के लिए, यह पता लगाना कि उत्परिवर्तित उधार बाद में शुरू हो सकता है, क्योंकि इसकी वास्तव में आवश्यकता नहीं है कि जल्दी। (यह विशेष विचार शायद काम भी नहीं करता है।)
स्वेन मार्नाच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.