CodeBlanks Logo Icon CodeBlanks

Traits as parameters

Use traits as function parameters.

Traits as parameters

A function can ask not for a specific type but for a specific behaviour. The impl Trait syntax means "any type implementing this trait":

trait Ozet {
    fn ozet(&self) -> String;
}

fn duyur(x: &impl Ozet) -> String {
    format!("Yeni: {}", x.ozet())
}

duyur now works with every type implementing Ozet: news, tweets, emails... Inside the function only the trait's methods can be used.

Generic syntax

impl Trait is in fact shorthand for a generic type parameter. The two forms are equivalent:

fn duyur(x: &impl Ozet) -> String { .. }
fn duyur<T: Ozet>(x: &T) -> String { .. }

The difference shows with several parameters: fn f(a: &impl Ozet, b: &impl Ozet) accepts two different types; fn f<T: Ozet>(a: &T, b: &T) requires both to be of the same type.

Practice Announcement

Define trait Ozet and implement it for Haber { konu: String } (summary: konu) and Tweet { yazar: String, metin: String } (summary: @yazar: metin). With fn duyur(x: &impl Ozet) -> String, print the news "Rust 2.0 çıktı" and the tweet ece/merhaba on separate lines.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
trait Ozet {
    fn ozet(&self) -> String;
}

struct Haber {
    konu: String,
}

struct Tweet {
    yazar: String,
    metin: String,
}

impl Ozet for Haber {
    fn ozet(&self) -> String {
        self.konu.clone()
    }
}

impl Ozet for Tweet {
    fn ozet(&self) -> String {
        format!("@{}: {}", self.yazar, self.metin)
    }
}

fn duyur(x: &impl Ozet) -> String {
    format!("Yeni: {}", x.ozet())
}

fn main() {
    let h = Haber { konu: String::from("Rust 2.0 çıktı") };
    let t = Tweet { yazar: String::from("ece"), metin: String::from("merhaba") };
    println!("{}", duyur(&h));
    println!("{}", duyur(&t));
}

Expected output

Yeni: Rust 2.0 çıktı
Yeni: @ece: merhaba

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Inside <code>fn duyur(x: &amp;impl Ozet)</code>, can the field <code>x.konu</code> be accessed?

  • No; the compiler only knows what Ozet offers Correct answer
  • Yes, if the type is Haber
  • Yes, always
  • Only with unsafe

Explanation: Since the function can be called with any type, only the methods in the contract can be used safely.

2 Ask for a behaviour

Question
fn duyur(x: &____ Ozet) -> String {
    format!("Yeni: {}", x.ozet())
}
Answer
fn duyur(x: &impl Ozet) -> String {
    format!("Yeni: {}", x.ozet())
}

Explanation: &impl Ozet accepts a reference to any type implementing Ozet.

3 Signature and what it accepts

Term Meaning
fn f(x: &impl Ozet) Any type implementing Ozet
fn f<T: Ozet>(x: &T) The same, generic form
fn f<T: Ozet>(a: &T, b: &T) Both the same type
fn f(x: &Haber) Only Haber

All lessons in Intermediate