问题
I'm reading a rust book and is confused by one example here.
use std::fmt::Display;
fn main() {
test("hello");
test2("hello")
}
fn test(s: &dyn Display) {
println!("{}", s);
}
fn test2(s: &str) {
println!("{}", s);
}
Here passing &'static str
as a trait object failed. It complains that "hello"
does not have a fixed size at compile time while it is a pointer type. Yet the second call works: why?
回答1:
&dyn Display
expects a reference. You feed it a &str
. So the compiler legitimately thinks that the type that implements Display
is str
. Hence, it complains that is does not have a fixed sized.
Add a reference, and it works fine:
use std::fmt::Display;
fn main() {
test(&"hello");
}
fn test(s: &dyn Display) {
println!("{}", s);
}
回答2:
str
does implement Display
, but it is not possible to coerce a &str
to a &dyn Display
because the implementation of Display
for str
may (and does) use the string's length. Length is part of the type &str
but not part of the type &dyn Display
, and you can't discard the length because that would make it impossible to implement Display
at all.
Another way to look at this is that a vtable (virtual method table) does not exist for the implementation of Display
for str
, because vtables may only contain functions that accept thin self
pointers, but in impl Display for str
, &self
is a fat pointer. See also Why can't `&(?Sized + Trait)` be casted to `&dyn Trait`?
However, &str
itself also implements Display
, so you can make test
work by simply adding another layer of indirection, as Boiethios's answer shows.
来源:https://stackoverflow.com/questions/57817405/use-trait-object-to-pass-str-in-rust