Những kiếp sống không từ vựng là gì?


88

Rust có một RFC liên quan đến các thời gian sống không từ vựng đã được chấp thuận để triển khai bằng ngôn ngữ này trong một thời gian dài. Gần đây , việc hỗ trợ tính năng này của Rust đã được cải thiện rất nhiều và coi như đã hoàn thiện.

Câu hỏi của tôi là: chính xác thì thời gian sống không từ vựng là gì?

Câu trả lời:


130

Dễ dàng nhất để hiểu các thời gian sống không từ vựng là gì bằng cách hiểu các thời gian sống từ vựng là gì. Trong các phiên bản của Rust trước khi có các vòng đời không phải từ vựng, mã này sẽ không thành công:

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

Trình biên dịch Rust thấy rằng biến đó scoresđược mượn score, vì vậy nó không cho phép đột biến thêm về 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

Tuy nhiên, một con người trivially có thể thấy rằng ví dụ này là quá bảo thủ: scorekhông bao giờ sử dụng ! Vấn đề là sự vay mượn của scoresby scoretừ vựng - nó kéo dài cho đến khi kết thúc khối mà nó được chứa trong đó:

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

Các vòng đời không từ vựng khắc phục điều này bằng cách nâng cao trình biên dịch để hiểu mức độ chi tiết này. Giờ đây, trình biên dịch có thể cho biết chính xác hơn khi nào cần mượn và mã này sẽ biên dịch.

Một điều tuyệt vời về các kiếp sống không từ vựng là một khi được kích hoạt, không ai sẽ nghĩ về chúng . Nó sẽ đơn giản trở thành "những gì Rust làm" và mọi thứ (hy vọng) sẽ hoạt động.

Tại sao lại được phép tồn tại từ vựng?

Rust nhằm mục đích chỉ cho phép biên dịch các chương trình an toàn đã biết. Tuy nhiên, không thể chỉ cho phép chính xác các chương trình an toàn và từ chối các chương trình không an toàn. Cuối cùng, Rust đã sai lầm ở khía cạnh bảo thủ: một số chương trình an toàn bị từ chối. Những cuộc đời hợp pháp là một ví dụ về điều này.

Các vòng đời Lexical dễ triển khai hơn nhiều trong trình biên dịch vì kiến ​​thức về các khối là "tầm thường", trong khi kiến ​​thức về luồng dữ liệu thì ít hơn. Trình biên dịch cần được viết lại để giới thiệu và sử dụng "biểu diễn trung gian cấp trung gian" (MIR) . Sau đó, trình kiểm tra mượn (hay còn gọi là "loanck") phải được viết lại để sử dụng MIR thay vì cây cú pháp trừu tượng (AST). Sau đó, các quy tắc của công cụ kiểm tra khoản vay phải được tinh chỉnh để trở nên chi tiết hơn.

Các vòng đời từ vựng không phải lúc nào cũng cản trở lập trình viên và có nhiều cách làm việc xung quanh các vòng đời từ vựng khi chúng xảy ra, ngay cả khi chúng gây phiền nhiễu. Trong nhiều trường hợp, điều này liên quan đến việc thêm dấu ngoặc nhọn hoặc giá trị boolean. Điều này cho phép Rust 1.0 xuất xưởng và hữu ích trong nhiều năm trước khi các vòng đời không từ vựng được triển khai.

Điều thú vị là, một số mẫu tốt nhất định đã được phát triển do có từ vựng lâu đời. Các ví dụ điển hình với tôi là các entrymô hình . Mã này không thành công trước thời gian tồn tại không từ vựng và được biên dịch với nó:

fn example(mut map: HashMap<i32, i32>, key: i32) {
    match map.get_mut(&key) {
        Some(value) => *value += 1,
        None => {
            map.insert(key, 1);
        }
    }
}

Tuy nhiên, mã này không hiệu quả vì nó tính toán hàm băm của khóa hai lần. Giải pháp được tạo ra thời gian tồn tại của từ vựng ngắn hơn và hiệu quả hơn:

fn example(mut map: HashMap<i32, i32>, key: i32) {
    *map.entry(key).or_insert(0) += 1;
}

Cái tên "những kiếp sống không từ vựng" nghe không hợp với tôi

Thời gian tồn tại của một giá trị là khoảng thời gian mà giá trị đó vẫn ở một địa chỉ bộ nhớ cụ thể (xem Tại sao tôi không thể lưu trữ một giá trị và một tham chiếu đến giá trị đó trong cùng một cấu trúc để được giải thích lâu hơn). Tính năng được gọi là thời gian tồn tại không từ vựng không thay đổi thời gian tồn tại của bất kỳ giá trị nào, vì vậy nó không thể làm cho thời gian tồn tại không từ vựng. Nó chỉ làm cho việc theo dõi và kiểm tra các khoản vay của các giá trị đó chính xác hơn.

Tên chính xác hơn cho đối tượng địa lý có thể là "từ mượn không có từ vựng ". Một số nhà phát triển trình biên dịch đề cập đến "Vayck dựa trên MIR".

Kiếp phi từ vựng không bao giờ có ý định trở thành một "người dùng phải đối mặt với" tính năng, cho mỗi gia nhập . Hầu hết chúng đã lớn dần lên trong tâm trí của chúng ta vì những nét vẽ nhỏ mà chúng ta nhận được từ sự vắng mặt của chúng. Tên của họ chủ yếu nhằm mục đích phát triển nội bộ và việc thay đổi nó cho mục đích tiếp thị không bao giờ được ưu tiên.

Vâng, nhưng làm thế nào để tôi sử dụng nó?

Trong Rust 1.31 (phát hành vào ngày 12 tháng 12 năm 2018), bạn cần chọn tham gia phiên bản Rust 2018 trong Cargo.toml của mình:

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

Kể từ phiên bản Rust 1.36, phiên bản Rust 2015 cũng cho phép các vòng đời không từ vựng.

Việc triển khai các vòng đời không từ vựng hiện tại đang ở "chế độ di chuyển". Nếu bộ kiểm tra mượn NLL vượt qua, quá trình biên dịch sẽ tiếp tục. Nếu không, công cụ kiểm tra khoản vay trước đó sẽ được gọi. Nếu trình kiểm tra mượn cũ cho phép mã, một cảnh báo sẽ được in, thông báo cho bạn biết rằng mã của bạn có khả năng bị hỏng trong phiên bản Rust trong tương lai và cần được cập nhật.

Trong các phiên bản Rust hàng đêm, bạn có thể chọn tham gia sự cố bị cưỡng chế thông qua cờ tính năng:

#![feature(nll)]

Bạn thậm chí có thể chọn tham gia phiên bản thử nghiệm của NLL bằng cách sử dụng cờ trình biên dịch -Z polonius.

Một mẫu các vấn đề thực tế được giải quyết bởi các kiếp sống không từ vựng


11
Tôi nghĩ cần phải nhấn mạnh rằng, có lẽ phản trực giác rằng, Vòng đời không hợp thời không phải về Thời gian tồn tại của các biến số, mà là về Thời gian sống của các khoản vay. Hoặc, nói cách khác, Các kiếp sống không hợp lý là về việc trang trí liên quan đến các vòng đời của các biến số từ những khoản vay mượn ... trừ khi tôi sai? (nhưng tôi không nghĩ rằng NLL thay đổi khi một trình hủy được thực thi)
Matthieu M.

2
" Thật thú vị, một số mô hình tốt nhất định đã được phát triển do các thời gian tồn tại từ vựng " —Tôi cho rằng, có nguy cơ rằng sự tồn tại của NLL có thể làm cho các mô hình tốt trong tương lai khó xác định hơn nhiều?
eggyal

1
@eggyal đó chắc chắn là một khả năng. Thiết kế trong một tập hợp các ràng buộc (ngay cả khi tùy ý!) Có thể dẫn đến các thiết kế mới, thú vị. Nếu không có những ràng buộc đó, chúng ta có thể dựa vào kiến ​​thức và khuôn mẫu hiện có của mình và không bao giờ học hỏi hoặc khám phá để tìm ra điều gì đó mới. Điều đó đang được nói, có lẽ ai đó sẽ nghĩ "ồ, hàm băm đang được tính hai lần, tôi có thể sửa lỗi đó" và API sẽ được tạo, nhưng người dùng có thể khó tìm thấy API ngay từ đầu. Mong các cụ như clippy giúp dân gian.
Shepmaster
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.