قرضگیری یک مقدار
همانطور که پیشتر دیدیم، به جای انتقال مالکیت هنگام فراخوانی یک تابع، میتوانید به تابع اجازه دهید که ارجاعی به مقدار داشته باشد:
#[derive(Debug)] struct Point(i32, i32); fn add(p1: &Point, p2: &Point) -> Point { Point(p1.0 + p2.0, p1.1 + p2.1) } fn main() { let p1 = Point(3, 4); let p2 = Point(10, 20); let p3 = add(&p1, &p2); println!("{p1:?} + {p2:?} = {p3:?}"); }
- تابع
add
ارجاع میگیرد به دو نقطه و یک نقطه جدید برمیگرداند. - فراخوانیکننده مالکیت ورودیها را حفظ میکند.
این اسلاید مرور مطالب مربوط به ارجاعات از روز اول است که به طور جزئی به شامل آرگومانهای تابع و مقادیر بازگشتی گسترش یافته است.
برای کاوش بیشتر
یادداشتهایی در مورد بازگشتهای stack و درونریزی (inlining):
-
برای نشان دادن این که بازگشت از
add
ارزان است، زیرا کامپایلر میتواند عملیات کپی را حذف کند، با درونریزی (inlining) فراخوانیadd
به تابعmain
، کد فوق را تغییر دهید تا آدرسهای پشته چاپ شوند و آن را در Playground اجرا کنید یا به اسمبلی در Godbolt نگاه کنید. در سطح بهینهسازی "DEBUG"، آدرسها باید تغییر کنند، در حالی که با تغییر به تنظیم "RELEASE" ثابت میمانند:#[derive(Debug)] struct Point(i32, i32); fn add(p1: &Point, p2: &Point) -> Point { let p = Point(p1.0 + p2.0, p1.1 + p2.1); println!("&p.0: {:p}", &p.0); p } pub fn main() { let p1 = Point(3, 4); let p2 = Point(10, 20); let p3 = add(&p1, &p2); println!("&p3.0: {:p}", &p3.0); println!("{p1:?} + {p2:?} = {p3:?}"); }
-
کامپایلر Rust میتواند بهطور خودکار درونریزی (inlining) انجام دهد، که میتواند در سطح تابع با
[inline(never)]#
غیرفعال شود. -
پس از غیرفعال کردن درونریزی، آدرسهای چاپ شده در تمامی سطوح بهینهسازی تغییر خواهند کرد. با نگاه کردن به Godbolt یا Playground، میتوان دید که در این حالت، بازگشت مقدار به ABI بستگی دارد، به عنوان مثال در amd64، دو
i32
که نقطه را تشکیل میدهند، در دو رجیستر (مانندeax
وedx
) بازگردانده خواهند شد.