تعريف دالة
fn greet(name: &str) {
println!("أهلًا {name}");
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
greet("سارة");
println!("{}", add(4, 6)); // 10
}
fnتعرّف الدالة، والأسماء بأسلوبsnake_case(حروف صغيرة وشرطة سفلية).- نوع كل معامل إلزامي: Rust تستنتج أنواع المتغيّرات داخل الدوال، لكنها لا تخمّن تواقيع الدوال. التوقيع عقد واضح لمن يستدعيها.
-> i32نوع القيمة المُرجعة. بلا سهم، الدالة تُرجع()(القيمة الفارغة، مثلvoid).- ترتيب الدوال في الملف لا يهمّ: يمكنك استدعاء دالة معرّفة بعد
main.
التعبير الأخير هو القيمة المُرجعة
لاحظ أن add لا تحتوي return. في Rust، آخر تعبير في جسم الدالة بلا فاصلة منقوطة هو قيمتها:
fn square(x: i32) -> i32 {
x * x // بلا ; : هذه هي القيمة المُرجعة
}
وreturn موجودة، لكنها تُستخدم عادة للخروج المبكّر فقط:
fn safe_divide(a: i32, b: i32) -> Option<i32> {
if b == 0 {
return None; // خروج مبكّر
}
Some(a / b) // المسار العادي: التعبير الأخير
}
fn main() {
println!("{:?} {:?}", safe_divide(10, 2), safe_divide(1, 0)); // Some(5) None
}
Option تعني "قيمة أو لا شيء"، وستفهمها بالتفصيل في درس Option وResult.
التعبير مقابل الجملة
هذا الفرق هو مفتاح فهم Rust:
- التعبير (expression) يُنتج قيمة:
5وa + bوadd(1, 2)، وحتى الكتلة{ ... }وifوmatch. - الجملة (statement) تنفّذ شيئًا ولا تُنتج قيمة:
let x = 5;جملة.
إضافة ; بعد تعبير تحوّله لجملة وتُسقط قيمته. ولأن الكتلة تعبير، يمكنك كتابة:
let total = {
let price = 100;
let tax = 16;
price + tax // قيمة الكتلة
};
println!("{total}"); // 116
والأمر نفسه مع if، فهي تعبير يُرجع قيمة:
let age = 20;
let label = if age >= 18 { "بالغ" } else { "قاصر" };
println!("{label}");
التفاصيل الكاملة للشروط والحلقات في درس التحكّم في التدفّق.
الفخّ الأشهر: فاصلة منقوطة زائدة
fn add(a: i32, b: i32) -> i32 {
a + b; // ❌ الفاصلة حوّلته لجملة، فالدالة تُرجع () لا i32
}
رسالة المترجم:
error[E0308]: mismatched types
--> src/main.rs:1:27
|
1 | fn add(a: i32, b: i32) -> i32 {
| --- ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
2 | a + b;
| - help: remove this semicolon to return this value
لاحظ السطر الأخير: مترجم Rust مشهور برسائل الخطأ الواضحة التي تقترح الحل غالبًا. اقرأ الرسالة كاملة قبل أن تبحث في الإنترنت.
عدّة قيم مُرجعة بصفّ (Tuple)
fn min_max(nums: &[i32]) -> (i32, i32) {
let mut min = nums[0];
let mut max = nums[0];
for &n in nums {
if n < min { min = n; }
if n > max { max = n; }
}
(min, max)
}
fn main() {
let (lo, hi) = min_max(&[4, 9, 1, 7]);
println!("{lo} {hi}"); // 1 9
}
&[i32] شريحة: "أي مجموعة متجاورة من i32" سواء مصفوفة أو Vec (درس الشرائح). وتفكيك الصفّ في let (lo, hi) يعطي كل قيمة اسمًا.
المعاملات والملكية
حين تمرّر قيمة مثل String لدالة، تنتقل ملكيتها إليها ولا تعود قابلة للاستخدام عند المستدعي، إلا إذا مرّرت مرجعًا (&). هذا قلب Rust، وهو موضوع درس الملكية ودرس الاستعارة. لهذا ترى &str في greet أعلاه: الدالة تستعير النص ولا تأخذه.
أخطاء شائعة
;بعد التعبير الأخير: خطأexpected i32, found (). احذفها.- نسيان نوع معامل:
fn add(a, b)لا تُترجم؛ الأنواع إلزامية في التواقيع. return x;في آخر الدالة: صحيحة لكنها غير اصطلاحية. اكتبxوحدها.- أسماء بأسلوب
camelCase: تعمل، لكن المترجم يحذّرك؛ الاصطلاحsnake_caseللدوال والمتغيّرات. - تمرير
Stringلدالة ثم استخدامها: خطأ "borrow of moved value". مرّر&s.
🎯 التالي: البنية و Cargo.