الدوال العامة
اجعل السلوك معتمدًا على النوع
الدوال العامة درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
Why Generic Functions
Generic functions let you write one function that works with many types instead of copying code per type. Rust replaces the placeholder type at compile time.
Imagine writing one largest for integers and another for chars. Generics collapse those into a single definition with no runtime cost.
Type Parameters
A generic function declares a type parameter inside angle brackets after the name. The name T is a convention, but any CamelCase identifier works.
The parameter can then appear in arguments and the return type, standing in for whatever concrete type the caller uses.
fn first<T>(pair: (T, T)) -> T {
pair.0
}A Simple Identity Function
This program defines a generic echo that returns its argument unchanged. It is called once with an integer and once with a string slice.
The compiler generates a separate concrete version for each type that is actually used.
fn echo<T>(value: T) -> T {
value
}
fn main() {
println!("{}", echo(42));
println!("{}", echo("hi"));
}Monomorphization
Rust uses monomorphization: at compile time it produces a specialized copy of the function for every concrete type used. There is no boxing or virtual dispatch.
The result is generic code that runs as fast as hand-written, type-specific code.
Generics Need Constraints
Inside a generic function you can only use operations that every possible type supports. A bare T cannot be added, compared, or printed.
This code fails to compile because T might not implement comparison. We will fix it with a trait bound next.
fn larger<T>(a: T, b: T) -> T {
if a > b { a } else { b }
}Adding a Trait Bound
To compare values we constrain T with PartialOrd. The bound promises the type supports the > operator.
We also add Copy so the values can be returned without moving issues for simple types like integers.
fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
if a > b { a } else { b }
}Calling the Bounded Function
Now the function works for any type implementing both traits. Integers and floats both satisfy PartialOrd + Copy.
The same source code, monomorphized into two versions, prints results for each call.
fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
if a > b { a } else { b }
}
fn main() {
println!("{}", larger(3, 9));
println!("{}", larger(2.5, 1.0));
}Multiple Type Parameters
A function can declare several type parameters. Each is independent, so the two arguments may have different types.
Here pair accepts any T and any U and returns them as a tuple.
fn pair<T, U>(a: T, b: U) -> (T, U) {
(a, b)
}Printing Generic Values
To print a generic value with {} the type must implement Display. We add that bound so any printable type can be passed.
This labels a value and returns it, demonstrating a bound used purely for formatting.
use std::fmt::Display;
fn announce<T: Display>(label: &str, value: T) {
println!("{}: {}", label, value);
}
fn main() {
announce("count", 7);
announce("name", "Ada");
}Turbofish Syntax
Sometimes the compiler cannot infer T from arguments alone. The turbofish ::<Type> lets you specify it explicitly at the call site.
It is most common with methods like parse and collect where the return type is ambiguous.
fn main() {
let n = "42".parse::<i32>().unwrap();
println!("{}", n + 1);
}Generics Over References
Generic parameters work with references too. Constraining by reference avoids requiring Copy when you only need to read values.
This longest_str-style helper borrows two slices and returns one without taking ownership.
fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
if a > b { a } else { b }
}Quick Check
Test your understanding of generic functions in Rust.
Recap
Generic functions use type parameters in angle brackets to work across many types with zero runtime cost via monomorphization.
Operations on a generic type require trait bounds like PartialOrd, Copy, or Display. Use the turbofish when inference cannot determine the type.
الأسئلة الشائعة
هل درس «الدوال العامة» مجاني؟
نعم — نص درس «الدوال العامة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.
ماذا ستتعلم في «الدوال العامة»؟
اجعل السلوك معتمدًا على النوع تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟
لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «الدوال العامة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟
نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.