ضمیمه ج: ویژگیهای قابل اشتقاق
در بخشهای مختلف کتاب، ما درباره ویژگی derive
صحبت کردیم که میتوانید آن را به تعریف یک struct یا enum اعمال کنید. ویژگی derive
کدی تولید میکند که یک ویژگی را با پیادهسازی پیشفرض خود روی نوعی که با سینتکس derive
حاشیهنویسی کردهاید، پیادهسازی میکند.
در این ضمیمه، مرجعی از تمام ویژگیهای موجود در کتابخانه استاندارد که میتوانید با derive
استفاده کنید ارائه میشود. هر بخش شامل موارد زیر است:
- چه عملگرها و متدهایی با مشتقسازی این ویژگی فعال میشوند
- پیادهسازی ویژگی که توسط
derive
ارائه میشود چه میکند - پیادهسازی ویژگی چه مفهومی درباره نوع دارد
- شرایطی که در آن اجازه یا عدم اجازه پیادهسازی ویژگی داده میشود
- مثالهایی از عملیاتهایی که به این ویژگی نیاز دارند
اگر رفتار متفاوتی از آنچه ویژگی derive
ارائه میدهد میخواهید، به مستندات کتابخانه استاندارد برای هر ویژگی مراجعه کنید تا جزئیات مربوط به نحوه پیادهسازی دستی آن را بیابید.
این ویژگیهایی که در اینجا فهرست شدهاند تنها ویژگیهایی هستند که توسط کتابخانه استاندارد تعریف شدهاند و میتوانند روی انواع شما با استفاده از derive
پیادهسازی شوند. ویژگیهای دیگر تعریفشده در کتابخانه استاندارد رفتار پیشفرض معقولی ندارند، بنابراین شما باید آنها را به نحوی پیادهسازی کنید که با آنچه میخواهید انجام دهید مطابقت داشته باشد.
مثالی از یک ویژگی که نمیتواند مشتق شود، Display
است که فرمتدهی برای کاربران نهایی را مدیریت میکند. شما باید همیشه راه مناسب برای نمایش یک نوع به کاربر نهایی را در نظر بگیرید. چه بخشهایی از نوع باید به کاربر نهایی نشان داده شود؟ چه بخشهایی برای او مرتبط است؟ چه فرمتی از داده برای او بیشترین اهمیت را دارد؟ کامپایلر Rust این بینش را ندارد، بنابراین نمیتواند رفتار پیشفرض مناسب را برای شما فراهم کند.
لیست ویژگیهای قابل اشتقاق ارائهشده در این ضمیمه جامع نیست: کتابخانهها میتوانند derive
را برای ویژگیهای خود پیادهسازی کنند و لیست ویژگیهایی که میتوانید با derive
استفاده کنید را بهطور واقعی باز بگذارند. پیادهسازی derive
شامل استفاده از یک ماکروی فرآیندی است که در بخش “ماکروها” از فصل 20 پوشش داده شده است.
Debug
برای خروجی برنامهنویسی
ویژگی Debug
فرمتدهی دیباگ را در رشتههای فرمت فعال میکند که با افزودن :?
درون نگهدارندههای {}
مشخص میکنید.
ویژگی Debug
به شما اجازه میدهد نمونههایی از یک نوع را برای مقاصد دیباگ چاپ کنید، بهطوریکه شما و سایر برنامهنویسانی که از نوع شما استفاده میکنند بتوانید نمونهای را در یک نقطه خاص از اجرای برنامه بررسی کنید.
ویژگی Debug
، برای مثال، در استفاده از ماکروی assert_eq!
مورد نیاز است. این ماکرو مقادیر نمونههای دادهشده بهعنوان آرگومانها را چاپ میکند اگر ادعای برابری شکست بخورد تا برنامهنویسان بتوانند ببینند چرا دو نمونه برابر نیستند.
PartialEq
و Eq
برای مقایسه برابری
ویژگی PartialEq
به شما اجازه میدهد نمونههای یک نوع را برای بررسی برابری مقایسه کنید و استفاده از عملگرهای ==
و !=
را ممکن میسازد.
مشتقسازی PartialEq
متد eq
را پیادهسازی میکند. وقتی PartialEq
روی structها مشتق میشود، دو نمونه فقط زمانی برابر هستند که تمام فیلدها برابر باشند و نمونهها برابر نیستند اگر هر یک از فیلدها برابر نباشند. وقتی روی enumها مشتق میشود، هر واریانت با خودش برابر است و با سایر واریانتها برابر نیست.
ویژگی PartialEq
، برای مثال، با استفاده از ماکروی assert_eq!
مورد نیاز است که باید بتواند دو نمونه از یک نوع را برای برابری مقایسه کند.
ویژگی Eq
هیچ متدی ندارد. هدف آن این است که نشان دهد برای هر مقدار از نوع حاشیهنویسیشده، مقدار با خودش برابر است. ویژگی Eq
فقط میتواند به نوعهایی اعمال شود که همچنین PartialEq
را پیادهسازی کرده باشند، اگرچه همه نوعهایی که PartialEq
را پیادهسازی کردهاند نمیتوانند Eq
را پیادهسازی کنند. مثالی از این مورد نوعهای عدد ممیز شناور هستند: پیادهسازی اعداد ممیز شناور بیان میکند که دو نمونه از مقدار غیرعدد (NaN
) برابر نیستند.
مثالی از زمانی که Eq
مورد نیاز است، برای کلیدها در HashMap<K, V>
است تا HashMap<K, V>
بتواند تعیین کند که آیا دو کلید یکسان هستند یا نه.
PartialOrd
و Ord
برای مقایسه مرتبسازی
ویژگی PartialOrd
به شما امکان میدهد نمونههای یک نوع را برای اهداف مرتبسازی مقایسه کنید. نوعی که ویژگی PartialOrd
را پیادهسازی میکند میتواند با عملگرهای <
، >
، <=
و >=
استفاده شود. شما فقط میتوانید ویژگی PartialOrd
را به نوعهایی اعمال کنید که همچنین PartialEq
را پیادهسازی کرده باشند.
مشتقسازی PartialOrd
متد partial_cmp
را پیادهسازی میکند، که یک Option<Ordering>
را برمیگرداند که در صورتی که مقادیر دادهشده ترتیببندی تولید نکنند، None
خواهد بود. مثالی از مقداری که ترتیببندی تولید نمیکند، حتی اگر بیشتر مقادیر آن نوع قابل مقایسه باشند، مقدار نقطه شناور غیرعدد (NaN
) است. فراخوانی partial_cmp
با هر عدد شناور و مقدار NaN
نقطه شناور None
را برمیگرداند.
وقتی روی structها مشتق میشود، PartialOrd
دو نمونه را با مقایسه مقدار هر فیلد به ترتیب ظاهر شدن فیلدها در تعریف struct مقایسه میکند. وقتی روی enumها مشتق میشود، واریانتهای enum که زودتر در تعریف enum اعلام شدهاند، کمتر از واریانتهایی در نظر گرفته میشوند که بعداً فهرست شدهاند.
ویژگی PartialOrd
، برای مثال، برای متد gen_range
از crate rand
مورد نیاز است که یک مقدار تصادفی در محدوده مشخصشده توسط یک عبارت محدوده تولید میکند.
ویژگی Ord
به شما امکان میدهد بدانید که برای هر دو مقدار از نوع حاشیهنویسیشده، یک ترتیببندی معتبر وجود خواهد داشت. ویژگی Ord
متد cmp
را پیادهسازی میکند، که به جای Option<Ordering>
، یک Ordering
را برمیگرداند زیرا یک ترتیببندی معتبر همیشه ممکن خواهد بود. شما فقط میتوانید ویژگی Ord
را به نوعهایی اعمال کنید که همچنین PartialOrd
و Eq
را پیادهسازی کرده باشند (و Eq
نیازمند PartialEq
است). وقتی روی structها و enumها مشتق میشود، cmp
به همان شکلی عمل میکند که پیادهسازی مشتقشده برای partial_cmp
در PartialOrd
عمل میکند.
مثالی از زمانی که Ord
مورد نیاز است، هنگام ذخیره مقادیر در BTreeSet<T>
است، یک ساختار داده که دادهها را بر اساس ترتیب مرتبسازی مقادیر ذخیره میکند.
Clone
و Copy
برای تکثیر مقادیر
ویژگی Clone
به شما امکان میدهد به طور صریح یک کپی عمیق از یک مقدار ایجاد کنید، و فرایند تکثیر ممکن است شامل اجرای کد دلخواه و کپی دادههای heap باشد. برای اطلاعات بیشتر درباره Clone
، به بخش “راههای تعامل متغیرها و دادهها: Clone” در فصل 4 مراجعه کنید.
مشتقسازی Clone
متد clone
را پیادهسازی میکند، که هنگام پیادهسازی برای کل نوع، متد clone
را روی هر یک از بخشهای نوع فراخوانی میکند. این بدان معناست که تمام فیلدها یا مقادیر در نوع نیز باید Clone
را برای مشتقسازی Clone
پیادهسازی کنند.
مثالی از زمانی که Clone
مورد نیاز است، هنگام فراخوانی متد to_vec
روی یک slice است. slice مالک نمونههای نوعی که شامل است را ندارد، اما وکتوری که از to_vec
برگردانده میشود باید مالک نمونههای خود باشد، بنابراین to_vec
روی هر آیتم clone
را فراخوانی میکند. بنابراین، نوع ذخیرهشده در slice باید Clone
را پیادهسازی کند.
ویژگی Copy
به شما امکان میدهد یک مقدار را با کپی کردن بیتهای ذخیرهشده روی stack تکثیر کنید؛ هیچ کد دلخواهی لازم نیست. برای اطلاعات بیشتر درباره Copy
، به بخش “دادههای فقط stack: Copy” در فصل 4 مراجعه کنید.
ویژگی Copy
هیچ متدی را تعریف نمیکند تا از اضافهبارگذاری آن متدها توسط برنامهنویسان و نقض فرضی که هیچ کد دلخواهی اجرا نمیشود جلوگیری کند. به این ترتیب، تمام برنامهنویسان میتوانند فرض کنند که کپی کردن یک مقدار بسیار سریع خواهد بود.
شما میتوانید Copy
را روی هر نوعی مشتق کنید که تمام اجزای آن Copy
را پیادهسازی میکنند. نوعی که Copy
را پیادهسازی میکند باید همچنین Clone
را پیادهسازی کند، زیرا نوعی که Copy
را پیادهسازی میکند دارای پیادهسازی سادهای از Clone
است که همان وظیفه را به عنوان Copy
انجام میدهد.
ویژگی Copy
به ندرت مورد نیاز است؛ نوعهایی که Copy
را پیادهسازی میکنند بهینهسازیهایی در دسترس دارند، به این معنا که شما نیازی به فراخوانی clone
ندارید، که کد را مختصرتر میکند.
هر چیزی که با Copy
ممکن است را میتوانید با Clone
نیز انجام دهید، اما کد ممکن است کندتر باشد یا نیاز به استفاده از clone
در مکانهای مختلف داشته باشد.
Hash
برای نگاشت مقدار به مقدار با اندازه ثابت
ویژگی Hash
به شما امکان میدهد یک نمونه از نوعی با اندازه دلخواه بگیرید و آن نمونه را با استفاده از یک تابع هش به مقدار با اندازه ثابت نگاشت کنید. مشتقسازی Hash
متد hash
را پیادهسازی میکند. پیادهسازی مشتقشده متد hash
نتیجه فراخوانی hash
روی هر یک از بخشهای نوع را ترکیب میکند، به این معنی که تمام فیلدها یا مقادیر نیز باید Hash
را پیادهسازی کنند تا Hash
مشتق شود.
مثالی از زمانی که Hash
مورد نیاز است، هنگام ذخیره کلیدها در HashMap<K, V>
برای ذخیره دادهها به صورت کارآمد است.
Default
برای مقادیر پیشفرض
ویژگی Default
به شما امکان میدهد یک مقدار پیشفرض برای یک نوع ایجاد کنید. مشتقسازی Default
تابع default
را پیادهسازی میکند. پیادهسازی مشتقشده تابع default
تابع default
را روی هر بخش از نوع فراخوانی میکند، به این معنی که تمام فیلدها یا مقادیر در نوع نیز باید Default
را پیادهسازی کنند تا Default
مشتق شود.
تابع Default::default
معمولاً به همراه سینتکس بهروزرسانی ساختار که در بخش “ایجاد نمونهها از نمونههای دیگر با سینتکس بهروزرسانی ساختار” در فصل 5 مورد بحث قرار گرفته است، استفاده میشود. میتوانید چند فیلد از یک ساختار را سفارشی کنید و سپس یک مقدار پیشفرض برای بقیه فیلدها با استفاده از ..Default::default()
تنظیم و استفاده کنید.
ویژگی Default
، برای مثال، زمانی مورد نیاز است که از متد unwrap_or_default
روی نمونههای Option<T>
استفاده میکنید. اگر Option<T>
برابر با None
باشد، متد unwrap_or_default
نتیجه Default::default
را برای نوع T
ذخیرهشده در Option<T>
برمیگرداند.