طول عمر در زنگ زدگی: جلوگیری از منابع آویزان

مقدمه
در یک برنامه زنگ زدگی هدف اصلی مدت زمان زندگی جلوگیری از مراجع آویزان، که می تواند باعث شود یک برنامه به داده های مرجع غیر از داده هایی که قصد دارد به آنها مراجعه کند ، مراجعه کند.
مرجع آویزان شرایطی است که یک مرجع به حافظه نامعتبر اشاره می کند. Tho Rust قوانین سختگیرانه وام را اجرا می کند ، و اطمینان می دهد که منابع همیشه VAID هستند.
با این حال ، مواردی وجود دارد که زنگ زدگی نمی تواند طول عمر مرجع را استنباط کند ، و این همان جایی است که مدت زمان زندگی وارد شوید
این مقاله توضیح می دهد:
✅ چه مدت زمان زندگی هستند و چرا آنها اهمیت دارند
✅ چگونه مراجع آویزان رخ می دهد و چگونه زنگ زدگی از آنها جلوگیری می کند.
✅ چگونه از حاشیه نویسی های مادام العمر استفاده کنید درست
✅ مشترک مشکلات و بهترین روشهابشر
با پایان خواندن این مقاله ، باید درک کنید که طول عمر چیست و چگونه می توانید از آنها در زنگ زدگی استفاده کنید.
مشکل: منابع آویزان
با استفاده از زبانهایی مانند C/C ++ ، می توان یک اشاره گر را به یک مکان حافظه نامعتبر ، که منجر به گسل های تقسیم بندی یا رفتار نامشخص می شود ، به راحتی اشاره کرد.
نمونه ای از یک مرجع آویزان در C ++
#include
int* getPointer() {
int x = 10; // x is local to this function
return &x; // Returning a reference to a local variable
}
int main() {
int* ptr = getPointer(); // ptr now points to a freed memory location
std::cout << *ptr; // Undefined behavior!
}
کد فوق چگونه نشان می دهد ptr
به حافظه اشاره می کند که دیگر معتبر نیست. این یک نمونه کلاسیک از یک مرجع آویزان است.
مکانیسم پیشگیری از زنگ زدگی
زنگ زدگی با استفاده از یکی از مؤلفه های کامپایلر آن به نام چک کننده قرض گرفتن به شدت از چنین مواردی جلوگیری می کند. به عنوان مثال:
fn main() {
let r;
{
let x = 10;
r = &x; // ❌ Error: `x` does not live long enough
}
println!("{}", r); // ❌ Borrow checker prevents use-after-free
}
با نگاهی به کد زنگ بالا ، می توانیم بگوییم کد شکست خورده است زیرا:
-
x
در داخل محدوده داخلی اعلام شده است{}
بشر -
r
به مرجع اختصاص داده شده استx
، اماx
از محدوده خارج می شود بعد از پایان بلوک. -
r
اکنون به حافظه نامعتبر اشاره می کند. زنگ زدگی این کار را در زمان کامپایل متوقف می کند!
این جایی است که Lifetimes بازی می شود. بنابراین بگذارید ببینیم این طول عمر چیست …
طول عمر در زنگ زدگی چیست؟
طول عمر راهی برای گفتن زنگ زدگی است که چه مدت مرجع (ها) باید معتبر باشد. آنها تغییر نمی کنند که چه مدت یک ارزش در واقع زندگی می کند – آنها فقط به کامپایلر کمک می کنند تا یک مرجع چقدر معتبر باقی بماند.
برخی از حقایق کلیدی در مورد طول عمر:
✅ هر مرجع در Rust دارای یک عمر است.
✅ چک کننده وام برای اطمینان از منابع معتبر ، طول عمر را مقایسه می کند.
✅ بیشتر طول عمر استنباط می شود (دقیقاً مانند انواع) ، بنابراین شما همیشه نیازی به مشخص کردن آنها ندارید.
✅ حیات صریح لازم است وقتی که زنگ زدگی نمی تواند آنها را به طور واضح استنباط کند (به عنوان مثال ، در امضاها یا ساختارها.)
درک حاشیه نویسی در طول عمر
نحو حاشیه نویسی طول عمر با یک apostrophe شروع می شود '
بشر بلافاصله با/توسط یک حرف یا کلمه دنبال کنید (بستگی به آنچه می خواهید از آن استفاده کنید) ، اما به طور معمول a
یا b
استفاده می شود در آخر ، برای توابع/ساختار آپوستروف '
، شخصیت a
یا b
در براکت زاویه ای محصور شده است. به عنوان مثال:
fn example<'a>(x: &'a i32) { }
struct Example<'a> { part: &'a str }
امضاهای عملکردی و طول عمر
بگذارید به شرایطی بپردازیم که عملکردی داشته باشیم که دو برش دو رشته ای طولانی تر پیدا کند:
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
اکنون با نگاهی به این عملکرد ، به طور معمول ، عملکرد قرار است درست کامپایل شود؟ خوب ، چکر وام می گوید بزرگ است نه!بشر
وقتی این کد را کامپایل می کنیم ، این خطای را در زیر دریافت می کنیم:
error[E0106]: missing lifetime specifier
--> example.rs:1:33
|
1 | fn longest(x: &str, y: &str) -> &str {
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
|
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
| ++++ ++ ++ ++
ما می گیریم error[E0106]: missing lifetime specifier
خطا این خطا در تلاش است تا بگوید چک وام نمی داند که آیا مرجع برگشتی از آن استفاده می شود x
یا y
از آنجا که بر اساس آنچه عملکرد انجام می دهد ، می تواند به دو روش پیش برود ، زیرا نمی تواند طول عمر آن را تعیین کند.
در رفع این خطا ، ما باید پارامتر Lifetime را در عملکرد خود قرار دهیم:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
اکنون معرفی می کنیم 'a
که یک پارامتر طول عمر عمومی است ، و x
وت y
پارامترهای گره خورده به همین طول عمر.
سرانجام ما پارامتر طول عمر عمومی را به مقدار بازده اضافه کردیم ، به همین دلیل مرجع برگشتی حداقل تا زمانی که هر دو ورودی معتبر باشند ، معتبر است. زنگ زدگی اکنون تضمین می کند که آنچه بازگردانده می شود ، بیشتر نمی شود x
یا y
، از منابع آویزان جلوگیری کنید.
طول عمر در ساختارها
در مورد ساختار ، در صورت داشتن مرجع (های) ، باید طول عمر را مشخص کند تا اطمینان حاصل شود که از داده های ارجاع شده بیشتر نمی شود. بگذارید این مثال را در زیر بررسی کنیم:
struct Person<'a> {
name: &'a str,
}
fn main() {
let name = String::from("Alice");
let person = Person { name: &name };
println!("{}", person.name); // ✅ Works fine
}
در این ساختار ، 'a
لازم است زیرا بدون آن ، زنگ نمی داند چه مدت Person
باید معتبر باشد چک کننده وام تضمین می کند که Person
ساختار هرگز پیشی نمی گیرد name
بشر
ELISION Lifetime (وقتی می توانید از آن پرش کنید)
مواردی وجود دارد که زنگ زدگی به طور خودکار طول عمر را نشان می دهد: این همان چیزی است که به آن گفته می شود انتخاببشر
به عنوان مثال برای یک تابع با تنها یک مرجع پارامتر ، s
بنابراین چک کننده وام فرض می کند که “/ مرجع تا زمانی که باشد ، زندگی می کند.
این به دنبال قوانین انتخابات عمر Rust است.
fn first_word(s: &str) -> &str { /* ... */ }
در 'static
طول عمر
'static
یک عمر خاص است که به معنای زندگی مرجع برای کل مدت برنامه است. اگرچه توصیه می شود از آن استفاده نکنید 'static
طول عمر به جز جایی که کاملاً ضروری است. به طور پیش فرض ، رشته های رشته ای دارند 'static
طول عمر
let s: &`static str = "Hello, Bene!";
خلاصه
طول عمر در زنگ تضمین می کند که منابع معتبر هستند و از مشکلات ایمنی حافظه در زمان کامپایل جلوگیری می کنند. در حالی که بیشتر طول عمر استنباط می شود ، حاشیه نویسی های صریح به حل ابهام در کارکردها و ساختارها کمک می کنند.