برنامه نویسی

درک طول عمر با قیاس در دنیای واقعی

زنگ زدگی اغلب به دلیل ضمانت ایمنی حافظه و عملکرد پایین آن مورد ستایش قرار می گیرد ، اما یکی از مفاهیمی که در ابتدا بسیاری از توسعه دهندگان را خراشیده می کند مدت زمان زندگیبشر اگر اینجا هستید ، احتمالاً با آن دست و پنجه نرم می کنید lifetimes و شاید تعجب کنید که چرا Rust باعث می شود صریحاً آنها را در زمینه های خاص حاشیه نویسی کنید.

در این پست ، من با شکستن آنها به مفاهیم ساده و هضم ، به تغییر زندگی کمک می کنم. ما از یک قیاس در دنیای واقعی استفاده خواهیم کرد تا آن را بچسبانیم ، از یک نمونه کد آسان بسازیم و بررسی کنیم که چگونه Lifetimes به زنگ زدگی کمک می کند تا از ایمنی حافظه اطمینان حاصل کند. با پایان این مقاله ، شما نه تنها درک خواهید کرد چه طول عمر ، اما چرا آنها وجود دارند و چگونه با اطمینان با آنها کار کنید.

بیایید شیرجه بزنیم!


چرا طول عمر وجود دارد؟

قبل از اینکه به جزئیات بپردازیم ، بیایید به سوال بزرگ بپردازیم: چرا Rust حتی طول عمر دارد؟

پاسخ کوتاه: برای جلوگیری از منابع آویزان. یک مرجع آویزان هنگامی اتفاق می افتد که یک نشانگر یا مرجع سعی در دسترسی به حافظه ای که قبلاً مورد استفاده قرار گرفته است ، دسترسی پیدا می کند. در بسیاری از زبانهای برنامه نویسی ، این می تواند منجر به رفتار نامشخص ، تصادفات یا اشکالات ظریف شود که اشکال زدایی بسیار دشوار است. زنگ زدگی از این کار کاملاً از طریق آن جلوگیری می کند چک کننده قرض گرفتنبشر

Lifetimes روش Rust برای ردیابی چه مدت مرجع معتبر است. آنها به عنوان یک قرارداد بین کامپایلر و برنامه نویس عمل می کنند ، و اطمینان می دهند که منابع هرگز از داده های مورد نظر خود پیشی نمی گیرند.


یک قیاس در دنیای واقعی: وام گرفتن یک کتابخانه

برای درک طول عمر ، بیایید از یک قیاس استفاده کنیم: وام گرفتن کتاب از یک کتابخانه.

تصور کنید که برای قرض گرفتن دو کتاب از یک کتابخانه دیدن می کنید: “کتاب A” و “کتاب B”. این کتابخانه به شما امکان می دهد هر کتاب را برای مدت زمان خاصی وام بگیرید ، بگویید:

  • می توانید 7 روز “کتاب A” را قرض بگیرید.
  • شما می توانید “کتاب B” را به مدت 10 روز وام بگیرید.

حال ، اگر قرار بود این دو را با هم مقایسه کنید ، فقط به هر دو کتاب دسترسی دارید کوتاهترین مدت همپوشانی (7 روز در این مورد). پس از آن ، یک کتاب (“کتاب A”) باید برگردانده شود ، و شما دیگر به آن دسترسی ندارید.

به طور مشابه ، در زنگ زدگی ، هنگامی که شما با منابع کار می کنید ، کامپایلر تضمین می کند که تمام منابع برای طول عمر همپوشانی داده هایی که به آنها اشاره می کنند معتبر هستند. اگر یک مرجع سعی کند داده های وام گرفته شده را فراتر بگذارد ، زنگ زدگی از تهیه کد شما امتناع می ورزد.


یک مثال ساده: پیدا کردن طولانی تر از دو برش رشته

بیایید این قیاس را با یک مثال زنگ زدگی مشخص کنیم. بگویید می خواهید تابعی بنویسید که دو برش رشته ای (&str) و طولانی تر از این دو را برمی گرداند. در اینجا چگونه می توانیم این کار را انجام دهیم:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("Hello");
    let string2 = String::from("World!");

    let result = longest(&string1, &string2);
    println!("The longer string is: {}", result);
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

شکستن کد

بیایید آنچه را که در اینجا اتفاق می افتد را جدا کنیم:

  1. امضای عملکرد:

    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
    
- The `'a` is a **lifetime parameter**. It tells Rust that the references `x` and `y` (the inputs) and the returned reference all share the same lifetime `'a`.
- This means that the returned reference will only be valid as long as both `x` and `y` are valid.
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

  1. مقدار بازگشت:

    • عملکرد طول آن را مقایسه می کند x وت y و یک مرجع را برمی گرداند (یا x یا y).
    • کامپایلر Rust از حاشیه نویسی های طول عمر استفاده می کند تا اطمینان حاصل شود که مرجع برگشتی هیچ یک از ورودی ها را بیشتر نمی کند.
  2. main عمل:

    • در اینجا ، ما دو متعلق به آن ایجاد می کنیم String ارزش ها (string1 وت string2) و ارجاعات را به longest عملکرد.
    • چک کننده وام تضمین می کند که منابع به تصویب رسیده (&string1 وت &string2) برای مدت زمان تماس عملکرد معتبر هستند.

تجسم طول عمر با قیاس کتابخانه

بازگشت به قیاس کتابخانه ما ، longest مانند یک کتابدار است که دو کتاب وام گرفته شده را با هم مقایسه می کند و به شما امکان می دهد با محتوای طولانی تر به آن دسترسی پیدا کنید. با این حال:

  • کتابدار فقط می تواند به شما دسترسی به کتاب برای دوره وام کوتاهتربشر
  • اگر یک کتاب (مرجع) زودتر قرار بگیرد ، نمی توانید کتاب دوم را فراتر از آن نقطه نگه دارید.

به همین ترتیب ، طول عمر 'a تضمین می کند که مرجع برگشتی فقط تا زمانی که هر دو آرگومان معتبر باشند معتبر است.


چه اتفاقی می افتد بدون طول عمر؟

حال ، بیایید ببینیم چه اتفاقی می افتد اگر یادداشت های طول عمر را حذف کنیم:

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این کد کامپایل نخواهد شد. زنگ زدگی خطایی مانند این را ایجاد می کند:

error[E0106]: missing lifetime specifier
 --> src/main.rs:1:16
  |
1 | fn longest(x: &str, y: &str) -> &str {
  |                ^ expected named lifetime parameter
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

کامپایلر در اصل می گوید: “من نمی دانم مرجع برگشتی چه مدت زنده خواهد ماند زیرا شما به من نگفتید!”

زنگ زدگی شما را ملزم می کند تا هر زمان که چک کننده وام نتواند به طور خودکار آنها را استنباط کند ، به صراحت طول بکشد. به همین دلیل ما نیاز داریم 'aبشر


مشکلات رایج و نحوه جلوگیری از آنها

1 بازگشت منابع به مقادیر موقت

این مثال ناقص را در نظر بگیرید:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    let temp = String::from("temporary");
    &temp // ERROR: Borrowing a temporary value
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در اینجا ، عملکرد سعی در بازگشت مرجع به یک متغیر محلی دارد (temp). اما از آن زمان temp هنگامی که عملکرد از کار خارج می شود ، مرجع آویزان می شود. زنگ زدگی با امتناع از تهیه کد از این امر جلوگیری می کند.

ثابت کردن: فقط منابع را به داده هایی که از دامنه عملکرد پیشی می گیرد ، برگردانید.


2 طول عمر ناسازگار

این سناریو را در نظر بگیرید:

fn main() {
    let string1 = String::from("Hello");
    let result;
    {
        let string2 = String::from("World!");
        result = longest(&string1, &string2);
    } // string2 goes out of scope here
    println!("The longer string is: {}", result); // ERROR
}
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این کد شکست می خورد زیرا string2 با پایان یافتن دامنه آن ، اما result اشاره ای به آن دارد. کامپایلر این مسئله را جلب می کند و از مرجع آویزان جلوگیری می کند.

ثابت کردن: اطمینان حاصل کنید که تمام منابع ارجاع شده به عملکرد به اندازه کافی طولانی زندگی می کنند.


غذای اصلی

  1. طول عمر از منابع آویزان جلوگیری می کند: حاشیه نویسی در طول عمر Rust اطمینان حاصل می کند که منابع هرگز از داده هایی که به آنها اشاره می کنند ، بیشتر نمی شوند.
  2. حاشیه نویسی های طول عمر توصیفی هستند: آنها روابط بین منابع را توصیف می کنند اما بر رفتار زمان اجرا تأثیر نمی گذارند.
  3. مشکلات مشترک: از بازگشت منابع به متغیرهای موقت یا ایجاد طول عمر ناسازگار خودداری کنید.

مراحل بعدی برای یادگیری

  • با نمونه های بیشتر مربوط به طول عمر آزمایش کنید. کارکردهایی را که منابع خود را به انواع مختلف داده ها باز می گرداند ، بنویسید.
  • موضوعات پیشرفته مانند طول عمر ساختاری وت قوانین انتخاب عمربشر
  • مرجع رسمی Lifetime Rust را برای بینش های عمیق تر بخوانید.

ممکن است در ابتدا به نظر برسد که ارعاب کننده باشد ، اما با تمرین ، آنها به طبیعت دوم تبدیل می شوند. برنامه نویسی را ادامه دهید ، و به زودی قدردانی خواهید کرد که چگونه Checker Borrow Borrow و Lifetimes شما را از اشکالات بی شماری نجات می دهد!

برنامه نویسی مبارک در زنگ زدگی! 🚀

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا