«تاپل» روشی سبک برای گروهکردن مجموعهای ثابت از انواع دلخواه داده در کنار هم است. تاپل اسم خاصی ندارد؛ وقتی به یک ساختار داده اسم میدهید، به struct تبدیل میشود. فیلدهای تاپل هم اسم ندارند؛ به آنها از طریق «تجزیه» یا بر اساس موقعیت دسترسی پیدا میکنید.
تاپلها همیشه با یک عبارت تاپل ساخته میشوند:
// pointless but legal
let unit = ();
// single element
let single_element = ("note the comma",);
// two element
let two_element = (123, "elements can be of differing types");
تاپلها میتوانند تعداد دلخواهی عنصر داشته باشند.
میتوان با تجزیه به عنصرهای یک تاپل دسترسی پیدا کرد. این یعنی نام متغیرهایی به تکتک عنصرهای تاپل نسبت میدهیم و در این فرآیند تاپل مصرف میشود.
let (elem1, _elem2) = two_element;
assert_eq!(elem1, 123);
با اندیس موقعیتی عددی هم میتوان به عنصرهای یک تاپل دسترسی پیدا کرد. اندیسگذاری، مثل همیشه، از ۰ شروع میشود.
let notation = single_element.0;
assert_eq!(notation, "note the comma");
از شما خواسته میشود با ساختارهای تاپلی هم کار کنید. اینها مثل ساختارهای معمولی نوعهای نامدار هستند؛ اما برخلاف ساختارهای معمولی، فیلدهای بینام دارند. نحوهی نگارششان بسیار شبیه به نحوهی نگارش تاپلهای معمولی است. استفاده از هر دو روش تجزیه و دسترسی موقعیتی مجاز است.
struct TupleStruct(u8, i32);
let my_tuple_struct = TupleStruct(123, -321);
let neg = my_tuple_struct.1;
let TupleStruct(byte, _) = my_tuple_struct;
assert_eq!(neg, -321);
assert_eq!(byte, 123);
همهی فیلدهای تاپلهای بینام همیشه عمومی هستند. اما فیلدهای ساختارهای تاپلی هرکدام دیدپذیری جداگانهای دارند که بهطور پیشفرض خصوصی است، درست مثل فیلدهای ساختارهای استاندارد. میتوانید فیلدها را مثل یک ساختار استاندارد با اصلاحکنندهی pub عمومی کنید.
// fails due to private fields
mod tuple { pub struct TupleStruct(u8, i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
// succeeds: fields are public
mod tuple { pub struct TupleStruct(pub u8, pub i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
شما روی یک بازی کار میکنید که برای یک سیستم توکار کممصرف طراحی شده است و باید چندین تابع کمکی بنویسید که بخشهای دیگر بازی از آنها استفاده خواهند کرد.
خارجقسمت، خروجی یک تقسیم است.
fn divmod(dividend: i16, divisor: i16) -> (i16, i16)
مثال:
assert_eq!(divmod(10, 3), (3, 1));
رئیستان قول میدهد که این کار برای فعال کردن یک بهینهسازی روی بافر صفحه به کارتان میآید.
تکرارگرها عنصرهایی هستند که متدهای تعریفشده توسط trait Iterator را در اختیار شما میگذارند. آن مستندات نسبتاً مفصل است، چون متدهای زیادی ارائه میدهند؛ در ادامه مهمترین ویژگیهایشان را میبینید:
enumerate دارند که برای هر مقدار یک تاپل (i, val) برمیگرداندfilter دارند که از یک کلوژر استفاده میکند تا تعیین کند آیا عنصری از تکرارگر بازگردانده شود یا نهmap دارند که از یک کلوژر برای تغییر دادن عنصرهای تکرارگر استفاده میکندچون تابع شما میتواند روی هر نوع تکرارگری اجرا شود، از impl استفاده میکند تا نشان دهد این یک نمونهی trait است و نه یک مورد ساده. به همین ترتیب، نحوهی نگارش <Item=T> فقط یعنی اینکه مهم نیست تکرارگر چه نوع عنصری تولید میکند؛ تابع شما میتواند عنصرهای زوج هر تکرارگری را تولید کند.
fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T>
مثالها:
let mut even_ints = evens(0_u8..);
assert_eq!(even_ints.next(), Some(0));
assert_eq!(even_ints.next(), Some(2));
assert_eq!(even_ints.next(), Some(4));
assert_eq!(even_ints.next(), Some(6));
let mut evens_from_odds = evens(1_i16..);
assert_eq!(evens_from_odds.next(), Some(1));
assert_eq!(evens_from_odds.next(), Some(3));
assert_eq!(evens_from_odds.next(), Some(5));
assert_eq!(evens_from_odds.next(), Some(7));
برای راحتی کار با نقشه، یک struct تاپلی به اسم Position دارید:
struct Position(i16, i16);
باید متدی به نام manhattan روی Position پیادهسازی کنید که فاصلهی منهتن آن موقعیت از مبدأ (Position(0, 0)) را برمیگرداند.
impl Position {
fn manhattan(&self) -> i16
}
مثال:
assert_eq!(Position(3, 4).manhattan(), 7);