답변
그것은 비 어휘 수명이 무엇인지 이해가 무엇인지 이해하는 가장 쉬운 어휘 수명이다. 비 어휘 수명이 존재하기 전의 Rust 버전에서는이 코드가 실패합니다 :
fn main() {
let mut scores = vec![1, 2, 3];
let score = &scores[0];
scores.push(4);
}
Rust 컴파일러는 변수 scores
가 차용 한 것을 인식 score
하므로 다음과 같은 추가 변형을 허용하지 않습니다 scores
.
error[E0502]: cannot borrow `scores` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let score = &scores[0];
| ------ immutable borrow occurs here
4 | scores.push(4);
| ^^^^^^ mutable borrow occurs here
5 | }
| - immutable borrow ends here
그러나 사람은이 예제가 지나치게 보수적이라는 것을 쉽게 알 수 있습니다. score
is never used ! 문제는 scores
by 의 차용 score
이 어휘 적이라는 것입니다. 이것은 그것이 포함 된 블록의 끝까지 지속됩니다.
fn main() {
let mut scores = vec![1, 2, 3]; //
let score = &scores[0]; //
scores.push(4); //
// <-- score stops borrowing here
}
비 어휘 수명은 컴파일러가이 수준의 세부 사항을 이해하도록 개선하여이 문제를 해결합니다. 컴파일러는 이제 차용이 필요한시기를보다 정확하게 알 수 있으며이 코드는 컴파일됩니다.
비어 휘적 삶의 놀라운 점은 일단 활성화되면 아무도 그것에 대해 생각하지 않을 것 입니다. 그것은 단순히 “러스트가하는 일”이되고 모든 것이 (희망적으로) 작동 할 것입니다.
어휘 수명이 허용 된 이유는 무엇입니까?
Rust는 알려진 안전한 프로그램 만 컴파일하도록 허용합니다. 그러나 불가능하다 정확하게 할 수 있도록 단지 안전 프로그램 및 안전하지 않은 것들을 거부합니다. 이를 위해 Rust는 보수적 인 측면에서 오류가 있습니다. 일부 안전한 프로그램은 거부됩니다. 어휘 수명이 이에 대한 한 가지 예입니다.
블록에 대한 지식은 “사소한”반면 데이터 흐름에 대한 지식은 적기 때문에 어휘 수명은 컴파일러에서 구현하기 훨씬 쉬웠습니다. 컴파일러 는 “중간 수준 중간 표현”(MIR)을 도입하고 사용하기 위해 다시 작성해야했습니다 . 그런 다음 AST (추상 구문 트리) 대신 MIR을 사용하도록 차용 검사기 (일명 “borrowck”)를 다시 작성해야했습니다. 그런 다음 차입 검사기의 규칙을 세분화해야했습니다.
어휘 수명이 항상 프로그래머에게 방해가되는 것은 아니며, 성가 시더라도 어휘 수명을 처리 할 수있는 많은 방법이 있습니다. 많은 경우에 추가 중괄호 또는 부울 값을 추가해야했습니다. 이로 인해 Rust 1.0이 출시되었고 비 어휘 수명이 구현되기 전 수년 동안 유용했습니다.
흥미롭게도 어휘 수명 때문에 특정 좋은 패턴이 개발되었습니다. 저에게 가장 좋은 예 는 entry
패턴 입니다. 이 코드는 비 어휘 수명 전에 실패하고 함께 컴파일됩니다.
fn example(mut map: HashMap<i32, i32>, key: i32) {
match map.get_mut(&key) {
Some(value) => *value += 1,
None => {
map.insert(key, 1);
}
}
}
그러나이 코드는 키의 해시를 두 번 계산하기 때문에 비효율적입니다. 어휘 수명으로 인해 생성 된 솔루션 은 더 짧고 효율적입니다.
fn example(mut map: HashMap<i32, i32>, key: i32) {
*map.entry(key).or_insert(0) += 1;
}
“비어 휘적 수명”이라는 이름은 나에게 맞지 않습니다.
값의 수명은 값이 특정 메모리 주소에 유지되는 시간 범위입니다 ( 더 자세한 설명 은 값과 해당 값에 대한 참조를 동일한 구조체에 저장할 수없는 이유는 무엇입니까? 참조 ). 비 어휘 수명으로 알려진 기능 은 값의 수명을 변경 하지 않으므로 수명을 비 어휘로 만들 수 없습니다. 이는 해당 값의 차입을 더 정확하게 추적하고 확인합니다.
기능의 더 정확한 이름은 “비 어휘 차용 “일 수 있습니다. 일부 컴파일러 개발자는 기본 “MIR 기반 차용”을 참조합니다.
비어 휘적 수명은 그 자체 로 “사용자를 향한”기능을 의도하지 않았습니다 . 그들은 우리가 부재로 인해 얻는 작은 종이 컷 때문에 우리 마음 속에서 대부분 커졌습니다. 그들의 이름은 대부분 내부 개발 목적으로 사용되었으며 마케팅 목적으로 변경하는 것은 결코 우선 순위가 아니 었습니다.
예,하지만 어떻게 사용합니까?
Rust 1.31 (2018-12-06에 릴리스 됨)에서는 Cargo.toml에서 Rust 2018 에디션을 옵트 인해야합니다.
[package]
name = "foo"
version = "0.0.1"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"
Rust 1.36부터 Rust 2015 에디션은 비 어휘 수명도 지원합니다.
비 어휘 수명의 현재 구현은 “마이그레이션 모드”에 있습니다. NLL 차용 검사기가 통과하면 컴파일이 계속됩니다. 그렇지 않은 경우 이전 차용 검사기가 호출됩니다. 이전 차용 검사기가 코드를 허용하면 경고가 인쇄되어 향후 Rust 버전에서 코드가 손상 될 가능성이 있으며 업데이트해야 함을 알려줍니다.
Rust의 야간 버전에서는 기능 플래그를 통해 강제 중단에 옵트 인 할 수 있습니다.
#![feature(nll)]
컴파일러 플래그를 사용하여 NLL의 실험적 버전을 선택할 수도 있습니다 -Z polonius
.
비 어휘 수명으로 해결 된 실제 문제 샘플
- HashMap 또는 Vec에서 참조를 반환하면 차용이 해당 범위를 초과하여 지속됩니까?
- HashMap :: get_mut ()이 나머지 범위에 대해 맵의 소유권을 갖는 이유는 무엇입니까?
- 함수 인수에서 변경 가능한 것으로 빌려 오기 때문에 변경 불가능한 것으로 빌릴 수 없습니다.
- Vec에서 업데이트 또는 삽입하는 방법은 무엇입니까?
- 범위를 벗어나기 전에 바인딩을 해제하는 방법이 있습니까?
- 재귀 구조를 반복 할 때 변경 가능한 참조를 얻을 수 없습니다. 한 번에 두 번 이상 변경 가능한 것으로 빌릴 수 없습니다.
- StdinLock을 사용한 결과를 반환 할 때 stdin에 대한 차입이 유지 된 이유는 무엇입니까?
- 쌍의 상자를 분해 할 때 부수적으로 이동 된 오류