중첩 배열 인덱스에서 "변경 가능으로 빌려서 변경 불가능한 것으로 빌릴 수 없음"은 무엇을 의미합니까?


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

그 색인이를 통해 구현된다 발견 IndexIndexMut특성과 그 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에 오신 것을 환영합니다. 훌륭한 질문에 감사드립니다!
Sven Marnach

정확하게; 나는 낮은 수준의 물건에 더 많은 관심을 시작한 이후)이) 그 전에 (2 배 하스켈 그 일을 내 3 년입니다 ~> 생각은 녹에게 소용돌이를 제공합니다
루카스 Boucke에게

@LucasBoucke 재미 있네요. 저는 보통 프로젝트에 Rust를 사용하지만이 AoC를 Haskell에 씁니다. 둘 다 도메인에서 훌륭한 언어입니다.
Boiethios

답변:


16

설탕 제거 버전은 현재와 약간 다릅니다. 라인

v[v[1]] = 999;

실제로 설탕을 빼다

*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차용됩니다. 공유 차용이 이미 확정되었으므로 전체 표현식이 차용 검사기를 통과하기 때문에 이것은 잘 작동합니다.

컴파일되는 버전은 "비-어휘 수명"이 도입 된 이후에만 컴파일됩니다. 이전 버전의 Rust에서 공유 차용은 표현식이 끝날 때까지 유효하며 유사한 오류가 발생합니다.

내 생각에 가장 깨끗한 해결책은 임시 변수를 사용하는 것입니다.

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

우와! 여기에 많은 일이 있습니다! 시간을내어 설명해 주셔서 감사합니다! (흥미롭게 이런 종류의 "질투"는 언어를 더 흥미롭게 만듭니다 ...). 왜 *v.index_mut(*v.index_mut(1)) = 999;"v를 두 번 이상 변경할 수 없다"고 실패 했는지에 대한 힌트를 줄 수 있을까요? ~> *v.index_mut(*v.index(1)) = 999;내부 빌림이 더 이상 필요하지 않다는 것을 알 수 있듯이 컴파일러 는 안됩니까?
Lucas Boucke 19

@LucasBoucke Rust는 때로는 약간 불편한 단점이 있지만 대부분의 경우이 경우와 같이 솔루션은 다소 간단합니다. 코드는 여전히 읽을 수 있으며 원래 가지고 있던 것과 조금 다르기 때문에 실제로 큰 문제는 아닙니다.
Sven Marnach

@LucasBoucke 죄송합니다. 지금까지 편집 한 내용이 없습니다. 의 결과 *v.index(1)는 IS 이 인덱스에 저장하고, 그 값의 차용 유지하기 위해 필요하지 않습니다 v살아 있습니다. 반면에의 결과는 이론적으로 할당 될 수 *v.index_mut(1)있는 가변적 인 장소 표현 이므로 차용을 유지합니다. 표면적으로, 차용 검사기에게 가치 표현 맥락에서의 장소 표현이 가치 표현으로 취급 될 수 있음을 가르 칠 수 있어야하므로, 이것은 차후의 Rust 버전에서 컴파일 될 가능성이 있습니다.
Sven Marnach

이에 desugar하는 어떻게 RFC에 대한{ let index = *Index::index(&v, 1); let value = 999; *IndexMut::index_mut(&mut v, index) = value; }
Boiethios

@FrenchBoiethios 나는 당신이 그것을 공식화하는 방법을 모른다. 그리고 나는 그것이 비행하는 것을 결코 찌르지 않을 것이라고 확신한다. 이 문제를 해결하려면 빌린 검사기 기능을 개선하는 것이 유일한 방법입니다. (이 특별한 생각은 아마도 중 하나가 작동하지 않습니다.)
스벤 Marnach에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.