davyzhang
davyzhang

Reputation: 2559

Why AsRef can not be used as parameter type annotation but fine with generic declaration?

playground

use std::path::Path;

// fn f1(p: AsRef<Path>) {
//     println!("{}", p.as_ref().display());
// }

fn f2<P: AsRef<Path>>(p: P) {
    println!("{}", p.as_ref().display());
}

fn main() {
    f2("/tmp/test.jpg");
}

The compiler will complain about the size of Path is not known for f1

Upvotes: 1

Views: 532

Answers (1)

Sven Marnach
Sven Marnach

Reputation: 602115

AsRef is a trait, not a type. Your definition of f1() uses it in place of a type. This legacy syntax is short for dyn AsRef<Path>, and denotes an arbitrary type implementing the trait AsRef<Path>, with dynamic dispatch at runtime. The size of an arbitrary type implementing the trait obviously isn't known at compile time, so you can use trait objects only behind pointers, e.g. &dyn AsRef<Path> or Box<dyn AsRef<Path>>. The compiler does not complain about the size of Path being unknown, it complains about the size of the trait object being unknown.

Trait bounds on generic types, on the other hand, expect traits, not types. P again is an arbitrary type implementing AsRef<Path>, but this arbitrary type needs to be known at compile time, and the compiler emits a new compiled version of f2() for every type that is actually used. This way, the size of each individual type is known at compile time.

Upvotes: 4

Related Questions