اشارهگر (Pointer)های هوشمند (Smart Pointers)
یک pointer یک مفهوم عمومی برای متغیری است که یک آدرس در حافظه را در خود نگه میدارد. این آدرس به دادهای دیگر اشاره میکند یا بهعبارتی «نشان میدهد». رایجترین نوع pointer در Rust یک رفرنس است، که در فصل ۴ با آن آشنا شدید. رفرنسها با نماد &
مشخص میشوند و مقدار مورد اشاره را قرض میگیرند. آنها هیچ قابلیت ویژهای جز اشاره به داده ندارند و هیچ سرباری نیز ندارند.
از سوی دیگر، اشارهگر (Pointer)های هوشمند ساختارهای دادهای هستند که مانند یک اشارهگر (Pointer) عمل میکنند، اما همچنین دارای فرا داده و قابلیتهای اضافی هستند. مفهوم اشارهگر (Pointer)های هوشمند منحصراً به Rust اختصاص ندارد: اشارهگر (Pointer)های هوشمند در ابتدا در C++ معرفی شدند و در زبانهای دیگر نیز وجود دارند. Rust مجموعهای از اشارهگر (Pointer)های هوشمند در کتابخانه استاندارد خود دارد که عملکردی فراتر از آنچه که ارجاعات فراهم میکنند، ارائه میدهند. برای بررسی مفهوم کلی، به چند مثال مختلف از اشارهگر (Pointer)های هوشمند نگاهی خواهیم انداخت، از جمله نوع اشارهگر (Pointer) هوشمند شمارش ارجاعات. این اشارهگر (Pointer) به شما امکان میدهد تا دادهها مالکیتهای متعددی داشته باشند، با ردیابی تعداد مالکان و پاک کردن داده هنگامی که هیچ مالکی باقی نماند.
زبان Rust با معرفی مفاهیمی مانند مالکیت و قرضگرفتن، تفاوت مهمی بین رفرنسها و smart pointerها ایجاد کرده است: در حالیکه رفرنسها تنها داده را قرض میگیرند، در بسیاری از موارد smart pointerها مالکیت دادهای را که به آن اشاره میکنند در اختیار دارند.
smart pointerها معمولاً با استفاده از struct
ها پیادهسازی میشوند. برخلاف struct
های معمولی، smart pointerها trait
های Deref
و Drop
را پیادهسازی میکنند. trait
مربوط به Deref
این امکان را فراهم میکند که یک نمونه از smart pointer مانند یک رفرنس رفتار کند، بهطوریکه بتوانید کد خود را بهگونهای بنویسید که با هر دو ــ یعنی هم رفرنسها و هم smart pointerها ــ کار کند. trait
مربوط به Drop
نیز به شما اجازه میدهد کدی را شخصیسازی کنید که هنگام خروج یک نمونه از smart pointer از حوزه (scope) اجرا میشود. در این فصل، هر دو trait
را بررسی خواهیم کرد و نشان خواهیم داد که چرا این ویژگیها برای smart pointerها اهمیت دارند.
از آنجا که الگوی اشارهگر (Pointer) هوشمند یک الگوی طراحی کلی است که بهطور مکرر در Rust استفاده میشود، این فصل تمام اشارهگر (Pointer)های هوشمند موجود را پوشش نمیدهد. بسیاری از کتابخانهها اشارهگر (Pointer)های هوشمند خاص خود را دارند و حتی میتوانید اشارهگر (Pointer) هوشمند خود را بنویسید. ما رایجترین اشارهگر (Pointer)های هوشمند در کتابخانه استاندارد را پوشش خواهیم داد:
Box<T>
برای تخصیص مقادیر در heapRc<T>
، یک نوع شمارشگر رفرنس که امکان مالکیت چندگانه را فراهم میکندRef<T>
وRefMut<T>
، که از طریقRefCell<T>
قابل دسترسی هستند؛ نوعی که قوانین قرضگرفتن را در زمان اجرا بهجای زمان کامپایل اعمال میکند
علاوه بر این، الگوی تغییرپذیری درونی (interior mutability) را بررسی خواهیم کرد، جایی که یک نوع غیرقابلتغییر، یک API برای تغییر مقدار درونی خود فراهم میکند. همچنین به چرخههای رفرنس (reference cycles) میپردازیم: اینکه چگونه میتوانند باعث نشت حافظه شوند و چگونه میتوان از آنها جلوگیری کرد.
بیایید شروع کنیم!