Rust มีRFCที่เกี่ยวข้องกับอายุขัยที่ไม่ใช่ศัพท์ซึ่งได้รับการอนุมัติให้ใช้งานในภาษาเป็นเวลานาน เมื่อเร็ว ๆ นี้การรองรับฟีเจอร์นี้ของ Rust ได้พัฒนาไปมากและถือว่าสมบูรณ์
คำถามของฉันคืออายุการใช้งานที่ไม่ใช่ศัพท์คืออะไร?
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
แต่มนุษย์นิดจะเห็นว่าตัวอย่างนี้เป็นอนุรักษ์นิยมมากเกินไป: score
จะไม่เคยใช้ ! ปัญหาคือการยืมscores
โดยscore
เป็นศัพท์ - จะคงอยู่จนกว่าจะสิ้นสุดบล็อกที่มีอยู่:
fn main() {
let mut scores = vec![1, 2, 3]; //
let score = &scores[0]; //
scores.push(4); //
// <-- score stops borrowing here
}
อายุการใช้งานที่ไม่ใช่ศัพท์แก้ไขปัญหานี้โดยการปรับปรุงคอมไพเลอร์ให้เข้าใจรายละเอียดระดับนี้ ขณะนี้คอมไพเลอร์สามารถบอกได้อย่างแม่นยำมากขึ้นว่าเมื่อใดจำเป็นต้องมีการยืมและรหัสนี้จะคอมไพล์
สิ่งที่ยอดเยี่ยมเกี่ยวกับอายุขัยที่ไม่ใช่คำศัพท์คือเมื่อเปิดใช้งานแล้วจะไม่มีใครคิดถึงสิ่งเหล่านี้ มันจะกลายเป็น "สิ่งที่ Rust ทำ" และสิ่งต่างๆ (หวังว่า) จะได้ผล
Rust มีไว้เพื่ออนุญาตให้คอมไพล์โปรแกรมที่รู้จักปลอดภัยเท่านั้น อย่างไรก็ตามเป็นไปไม่ได้เลยที่จะอนุญาตเฉพาะโปรแกรมที่ปลอดภัยและปฏิเสธโปรแกรมที่ไม่ปลอดภัย ด้วยเหตุนี้ Rust จึงทำผิดในด้านของการอนุรักษ์นิยม: โปรแกรมปลอดภัยบางโปรแกรมถูกปฏิเสธ คำศัพท์ตลอดชีวิตเป็นตัวอย่างหนึ่งของสิ่งนี้
อายุการใช้งานของคำศัพท์นั้นง่ายกว่ามากในการนำไปใช้ในคอมไพเลอร์เนื่องจากความรู้เกี่ยวกับบล็อกนั้น "ไม่สำคัญ" ในขณะที่ความรู้เกี่ยวกับการไหลของข้อมูลมีน้อยกว่า คอมไพเลอร์จะต้องเขียนใหม่ที่จะแนะนำและทำให้การใช้งานของ "ระดับกลางการแสดงกลาง" (MIR) จากนั้นตัวตรวจสอบการยืม (หรือที่เรียกว่า "ยืม") จะต้องเขียนใหม่เพื่อใช้ MIR แทนโครงสร้างไวยากรณ์นามธรรม (AST) จากนั้นกฎของผู้ตรวจการยืมจะต้องได้รับการขัดเกลาให้มีความละเอียดรอบคอบ
อายุการใช้งานของคำศัพท์ไม่ได้เป็นอุปสรรคต่อโปรแกรมเมอร์เสมอไปและมีหลายวิธีในการทำงานกับช่วงชีวิตของศัพท์แม้ว่าพวกเขาจะน่ารำคาญก็ตาม ในหลาย ๆ กรณีสิ่งนี้เกี่ยวข้องกับการเพิ่มวงเล็บปีกกาพิเศษหรือค่าบูลีน สิ่งนี้ทำให้ 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-basedorrowck"
อายุการใช้งานที่ไม่เป็นคำศัพท์ที่ไม่เคยมีเจตนาที่จะเป็น "ผู้ใช้หันหน้าไปทางคุณลักษณะ" ต่อ se พวกเขาเติบโตขึ้นอย่างมากในความคิดของเราเพราะกระดาษตัดกระดาษเล็ก ๆ น้อย ๆ ที่เราได้รับจากการที่พวกเขาไม่อยู่ ชื่อของพวกเขาส่วนใหญ่มีวัตถุประสงค์เพื่อการพัฒนาภายในและการเปลี่ยนชื่อเพื่อวัตถุประสงค์ทางการตลาดไม่เคยมีความสำคัญ
ใน Rust 1.31 (เผยแพร่เมื่อ 2018-12-06) คุณต้องเลือกใช้รุ่น Rust 2018 ใน Cargo.toml ของคุณ:
[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)]
-Z polonius
คุณยังสามารถเลือกในการให้เป็นเวอร์ชันทดลองของสาวน้อยโดยใช้ธงคอมไพเลอร์