6

The below code compiles and runs fine:

use std::fmt::Display; fn display(x: &str) { println!("{}", x); } fn main() { let s: &str = "hi there"; display(s); } 

However, if you change the display function to be

fn display(x: &Display) 

It gives the following error:

src/main.rs:9:13: 9:14 error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277] src/main.rs:9 display(s); 

By changing display(s) to display(&s) it works again.

What is going on here? Clearly the type is &str, but when &Display is the input argument it doesn't recognize that.

Note: &34 also works as an argument just fine. Is this because Display is actually implemented for &str and not str?

3 Answers 3

7

You are requesting that &str should be coerced to &Display (a reference to trait object), which seems to make sense since the type str implements Display.

Yet as of Rust 1.9 (and no current plans of changing this), the conversion to a trait object is only possible for &T to &Trait if the type T is “Sized”.

The reason is the implementation. A trait object like &Display consists of two fields, one pointer to the data, and one pointer to the table of trait methods (vtable). This representation is only possible for values whose references are “thin” which are exactly the types where T: Sized. A &str is a “fat” reference, it has a pointer and a length, and so a str can not be a trait object's data.


Why does display(&s) work though? I guess that is a referene to the "fat" reference?

Yes, exactly. A &&str, is a ”thin” reference that points to the variable with the &str value. So it can be converted to &Display.

Sign up to request clarification or add additional context in comments.

4 Comments

Why does display(&s) work though? I guess that is a referene to the "fat" reference? Are there other types that are "fat" referenes, or is &str special somehow?
I guess I don't understand why str isn't just a struct with the data and the length, instead of &str? Then &str would no longer be a fat pointer and we wouldn't have this problem!
I looked up fat pointers and this was a pretty good reference: reddit.com/r/rust/comments/38tv6n/… I'll keep investigating...
this was also a good reference: stackoverflow.com/questions/31949579/…
5

(Promoted my edits to the main answer)

When you write fn display(x: &Display), the function takes a value that can be coerced into a trait object by dereferencing it. Also Rust function requires the value size of the parameter x to be known at the compile time.

When &34 (&u32 type) is dereferenced and coerced into trait object, it becomes u32 and its size can be determined.

When &str is dereferenced, it becomes str and its size cannot be determined as the length of a string can be anything.

By adding & to &str (&&str), it is dereferenced back to &str, which is a pointer and its size can be determined. I believe this is why the compiler only accepts display(&s) in your code.

4 Comments

This.. its coersion happening. Perhaps promote your edit into the main answer?
Thank you for the suggestion. I promoted my edit (with some extra modifications for clarity) into the main answer.
The book says "A trait is object-safe if both of these are true: 1) trait does not require that Self: Sized; 2) all of its methods are object-safe". However only reference to Sized value can be casted to trait object
I would add to this answer (from my reading after getting help from everyone) that str is really just a wrapper for [u8], who's size cannot be known at compile time. Thus, the "fat" reference.
1

By changing display(s) to display(&s) it works again.

It all goes down to &str: Display (+ Sized) and str: !Display (this is just a notation)

  • display(s) expects s: &Display, => &str: &Display which is false.
  • display(&s) expects &s: &Display => &(&str) : &Display which is true as &str: Display

1 Comment

Display implemented for str, not for &str. doc.rust-lang.org/src/core/up/src/libcore/fmt/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.