Why doesn't Rust recognize that the variable is & str?

Below code compiles and works 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

 fn display(x: &Display) 

It produces 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); 

Changing display(s) to display(&s) , it works again.

What's going on here? Obviously, the type is &str , but when &Display is an input argument, it does not recognize it.

Note: &34 also works fine as an argument. Is it because display actually implemented for &str , not str ?

+6
source share
3 answers

You are requesting that &str be forcibly bound to &Display (a reference to an object-object), which seems to make sense since the str type implements Display .

However, as with Rust 1.9 (and no current plans to change this), conversion to a feature object is only possible with &T to &Trait if the type T is " Sized ".

The reason is the implementation. An attribute object of type &Display consists of two fields, one pointer to data and one pointer to a table of attribute methods (vtable). This representation is only possible for values ​​whose references are thin, which are exactly where T: Sized types. A &str is a bold reference, has a pointer and length, so str cannot be data of an object-object.


Why does mapping (& s) work? I think this is a referral to the "thick" link?

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

+6
source

(Pushed my changes to the main answer)

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

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

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

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

+5
source

Changing the display to display (& s), it works again.

Everything goes up 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
source

All Articles