Both are clones, why is the former possible and the latter not

Both are clones, why is the former possible and the latter not

trait GetName {
    fn get_name(&self) -> &String;
}

#[derive(Clone)]
struct Student {
    name : String,
}

impl GetName for Student {
    fn get_name(&self) -> &String {
        &self.name
    }
}

fn print(item : impl GetName) {
    println!("name = {:?}", item.get_name());
}

fn produce() -> impl GetName {
    Student {
        name : String::from("shawy"),
    }
}

fn main() {
    let s = Student {
        name : String::from("alice"),
    };
    print(s.clone()); // Why does it run correctly here ?

    let s = produce();
    print(s.clone()); // Why is it running incorrectly here ? 
}

ERROR:

  --> src\main.rs:33:13
   |     let s = produce();
33 |     print(s.clone());
   |             ^^^^^ method not found in `impl GetName`
fn produce() -> impl GetName + Clone {
    Student {
        name : String::from("shawy"),
    }
}
1 Like

In the second case, the type is an opaque type, and you can only utilize the traits in the impl Trait (and supertraits and leaked autotraits). This allows the function to change the concrete type returned behind the opaque type (e.g. to something that doesn't implement Clone) without breaking downstream code.

The solution above adds Clone to the opaque type's capabilities.

2 Likes

Sidenote: use &str not &String. It's more general and involves less indirection.

1 Like