مفاهیم جابهجایی
انتساب, مالکیت را بین متغیرها منتقل میکند:
fn main() { let s1: String = String::from("سلام!"); let s2: String = s1; println!("s2: {s2}"); // println!("s1: {s1}"); }
- انتساب
s1بهs2مالکیت را منتقل میکند. - زمانی که دیگر در اسکوپ
s1نیستیم, هیچ اتفاقی نمیافتد: چونs1مالک چیزی نیست. - زمانی که دیگر در اسکوپ
s2نیستیم, دادههای رشته آزاد میشوند.
قبل از انتقال به s2 :
بعد از انتقال به s2 :
هنگامی که یک مقدار را به یک تابع منتقل میکنید، مقدار به آرگمان تابع اختصاص داده میشود. به این شکل مالکیت را منتقل میکند:
fn say_hello(name: String) { println!("سلام {name}") } fn main() { let name = String::from("الیس"); say_hello(name); // say_hello(name); }
-
اشاره کنید که این رویه راست بر خلاف پیشفرض زبان C++ است که در ان مقدار کپی میشود مگر که از
std::moveاستفاده کنیم ( تا یک مقدار را جا به جا کنیم!) -
این رویه فقط برای انتقال مالکیت است. اینکه آیا هیچ کد ماشینی برای دستکاری خود دادهها تولید میشود یا خیر، موضوعی برای بهینهسازی است و چنین کپیهایی بهطور تهاجمی (aggressively) بهینهسازی میشوند.
-
مقادیر ساده (مانند اعداد صحیح) را میتوان
Copyکرد (اسلایدهای بعدی را ببینید). -
در Rust، کلونها واضح بیان میشوند (با استفاده از
clone).
در مثال say_hello:
- با اولین فراخوانی
say_hello، تابعmainمالکیتnameرا انتقال میدهد. پس از آن،nameدیگر نمیتواند درmainاستفاده شود. - حافظه انباشت اختصاص داده شده برای
nameدر انتهای تابعsay_helloآزاد خواهد شد. - تابع
mainمیتواند مالکیتnameرا حفظ کند اگر آن را به عنوان یک مرجع (&name) منتقل کند و صد البته کهsay_helloیک مرجع را به عنوان پارامتر باید بپذیرد. - به عنوان گزینه دیگر،
mainمیتواند یک کلون ازnameرا در فراخوانی اولیه تابع ای که در نظر داریم (name.clone()) منتقل کند. - در زبان Rust سختتر از C++ است که سهوا کپی ایجاد کنیم, زیر به صورت پیشفرض از مفهوم «انتقال» استفاده میکنیم و برنامه نویس مجبور است هر جا که لازم هست به صورت صریح کلون را ایجاد کند.
برای کاوش بیشتر
نسخههای دفاعی در ++C مدرن
C++ مدرن این مشکل را به شیوه متفاوتی حل میکند:
std::string s1 = "Cpp";
std::string s2 = s1; // Duplicate the data in s1.
- دادههای انباشت از دادههای
s1یک کپی برابر اصل برایs2گرفته میشود که این کپی به صورت مستقل است. - حالا هر موقع
s1یاs2از اسکوپ موردنظرشون خارج شوند هر کدام به صورت جداگانهای حافظه خود را آزاد میکنند.
قبل از انتساب همراه کپی:
بعد از انتساب همراه کپی:
نکات کلیدی:
-
زبان C++ انتخاب کمی متفاوت نسبت به زبان Rust انجام داده است. زیرا
=دادهها را کپی میکند، دادههای رشته باید کلون شوند. در غیر این صورت، هر موقع از اسکوپ یکی از آنها خارج شویم امکان به وجود آمدن اشتباه آزادسازی مجدد حافظه رخ دهد. -
البته که زبان C++ دارای
std::moveاست که برای انتقال یک متغییر استفاده میشود. اگر مثال ماs2 = std::move(s1)بود هیچ تخصیص انباشتی صورت نمیگرفت بلکهs1در یک وضعیت معتبر البته نامشخص قرار میگرفت و برخلاف زبان Rust, توی زبان C++ برنامهنویس مجاز است که دوباره ازs1استفاده کند. -
بر خلاف Rust،
=در C++ میتواند برای کپی کردن و هم انتقال دادن استفاده شود.