Development Tip

비 어휘 수명이란 무엇입니까?

yourdevel 2020. 12. 1. 19:48
반응형

비 어휘 수명이란 무엇입니까?


Rust는 오랫동안 언어로 구현 되도록 승인 된 비 어휘 수명과 관련된 RFC가지고 있습니다. 최근 에이 기능에 대한 Rust의 지원은 많이 향상되었으며 완전한 것으로 간주됩니다.

제 질문은 비어 휘적 수명이란 정확히 무엇입니까?


그것은 비 어휘 수명이 무엇인지 이해가 무엇인지 이해하는 가장 쉬운 어휘 수명이다. 비 어휘 수명이 존재하기 전의 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

그러나 사람은이 예제가 지나치게 보수적이라는 것을 쉽게 알 수 있습니다. scoreis never used ! 문제는 scoresby 의 차용 score어휘 적이라는 것입니다. 이것은 그것이 포함 된 블록의 끝까지 지속됩니다.

fn main() {
    let mut scores = vec![1, 2, 3]; //
    let score = &scores[0];         //
    scores.push(4);                 //
                                    // <-- score stops borrowing here
}

비 어휘 수명은 컴파일러가이 수준의 세부 사항을 이해하도록 개선하여이 문제를 해결합니다. 컴파일러는 이제 차용이 필요한시기를보다 정확하게 알 수 있으며이 코드는 컴파일됩니다.

비어 휘적 삶의 놀라운 점은 일단 활성화되면 아무도 그것에 대해 생각하지 않을 것 입니다. 그것은 단순히 "러스트가하는 일"이되고 모든 것이 (희망대로) 제대로 작동 할 것입니다.

어휘 수명이 허용 된 이유는 무엇입니까?

Rust는 알려진 안전한 프로그램 만 컴파일하도록 허용합니다. 그러나 불가능하다 정확하게 할 수 있도록 단지 안전 프로그램 및 안전하지 않은 것들을 거부합니다. 이를 위해 Rust는 보수적 인 측면에서 오류가 있습니다. 일부 안전한 프로그램은 거부됩니다. 어휘 수명이 이에 대한 한 가지 예입니다.

블록에 대한 지식은 "사소한"반면 데이터 흐름에 대한 지식은 적기 때문에 어휘 수명은 컴파일러에서 구현하기 훨씬 쉬웠습니다. 컴파일러 는 "중간 수준 중간 표현"(MIR)을 도입하고 사용하기 위해 다시 작성해야했습니다 . 그런 다음 차용 검사기 (일명 "borrowck")를 다시 작성하여 추상 구문 트리 (AST) 대신 MIR을 사용해야했습니다. 그런 다음 차입 검사기의 규칙을 세분화해야했습니다.

어휘 수명이 항상 프로그래머에게 방해가되는 것은 아니며, 성가 시더라도 어휘 수명을 처리 할 수있는 많은 방법이 있습니다. 많은 경우에 추가 중괄호 또는 부울 값을 추가해야했습니다. 이로 인해 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 기반 차용"을 참조합니다.

Non-lexical lifetimes were never intended to be a "user-facing" feature, per se. They've mostly grown large in our minds because of the little papercuts we get from their absence. Their name was mostly intended for internal development purposes and changing it for marketing purposes was never a priority.

Yeah, but how do I use it?

In Rust 1.31 (released on 2018-12-06), you need to opt-in to the Rust 2018 edition in your Cargo.toml:

[package]
name = "foo"
version = "0.0.1"
authors = ["An Devloper <an.devloper@example.com>"]
edition = "2018"

As of Rust 1.36, the Rust 2015 edition also enables non-lexical lifetimes.

The current implementation of non-lexical lifetimes is in a "migration mode". If the NLL borrow checker passes, compilation continues. If it doesn't, the previous borrow checker is invoked. If the old borrow checker allows the code, a warning is printed, informing you that your code is likely to break in a future version of Rust and should be updated.

In nightly versions of Rust, you can opt-in to the enforced breakage via a feature flag:

#![feature(nll)]

You can even opt-in to the experimental version of NLL by using the compiler flag -Z polonius.

A sample of real problems solved by non-lexical lifetimes

참고URL : https://stackoverflow.com/questions/50251487/what-are-non-lexical-lifetimes

반응형