مفاهیم جابهجایی
انتساب, مالکیت را بین متغیرها منتقل میکند:
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++ میتواند برای کپی کردن و هم انتقال دادن استفاده شود.