تابع، بدنهای از کد است که شامل یک یا چند دستور یا عبارت است. تابع میتواند بهصورت اختیاری مقدار بازگشتی داشته باشد.
در سبک Rust، برای اسم تابع از snake case استفاده میشود و کلیدواژهی fn در تعریف تابع پیش از آن میآید. برای نمونه
fn do_nothing() {}
پرانتزها صفر یا چند پارامتر را در بر میگیرند که با ویرگول از هم جدا میشوند. پارامتر، اتصالی به یک مقدار از نوعی مشخص است که به تابع فرستاده میشود. حتی اگر هیچ پارامتری وجود نداشته باشد، پرانتزها در تعریف تابع همچنان الزامیاند. به مقدار واقعیای که به یک پارامتر فرستاده میشود، «آرگومان» میگویند.
ترکیب پارامترها و مقدار بازگشتی، «امضای تابع» نامیده میشود. در امضای تابع، نوع هر پارامتر باید مشخص شده باشد.
آکولادها بدنهی تابع را در بر میگیرند: دستورها و عبارتهای آن. حتی اگر تابع هیچ دستور یا عبارتی نداشته باشد، آکولادها در تعریف تابع همچنان الزامیاند.
در نمونهی زیر، تابع یک پارامتر از نوع i32 میگیرد، آن را به اسم value متصل میکند و چاپش میکند.
fn print_integer(value: i32) {
println!("{value:?}");
}
به تعریف پارامتر دقت کنید. هر پارامتر در قالب name: Type تعریف میشود.
یک تابع میتواند مقداری را هم بازگرداند. بهصورت پیشفرض، خروجی آخرین عبارت بازگردانده میشود. در نمونهی زیر، تابع یک پارامتر i32 دارد و دو برابر آن را بازمیگرداند.
fn double_integer(value: i32) -> i32 {
value * 2
}
-> i32 نشان میدهد که تابع یک i32 بازمیگرداند. برخلاف پارامترها، مقدار بازگشتی اسمی ندارد.
میتوان با کلیدواژهی return زودتر از تابع خارج شد، به این شکل:
fn long_function() -> i32 {
let some_condition = false;
// code snipped
if (some_condition) {
return 0;
}
// more code snipped
42
}
از const fn برای تعریف یک تابع ثابت استفاده میشود که میتواند در زمان کامپایل ارزیابی شود.
const fn compute_data_checksum() -> u128 {
const DATA: &[u8] = include_bytes!("my_big_data_file");
// checksum implementation is left as an exercise for the reader
}
/// This checksum is used to validate that the user has not tampered with proprietary configuration.
pub const DATA_CHECKSUM: u128 = compute_data_checksum();
چون تابع ثابت ممکن است در زمان کامپایل ارزیابی شود، محدودیتهایی دارد که تابع معمولی ندارد. بهویژه، یک const fn فقط میتواند توابع دیگری را فراخوانی کند که آنها هم با const مشخص شده باشند. نادیده گرفتن این محدودیت به خطای کامپایل منجر میشود.
const fn multiply_integer(value: i32) -> i32 {
use std::time::SystemTime;
if SystemTime::now().elapsed().unwrap().as_nanos() == 0 { // this line errors
value * 2
} else {
value * 3
}
}
توابع بینامی هم وجود دارند که در مبحث closures به آنها پرداخته شده است.