为什么Rust不认识变量是& str?

时间:2016-06-17 04:02:55

标签: rust traits

以下代码编译并运行良好:

use std::fmt::Display;

fn display(x: &str) {
    println!("{}", x);
}

fn main() {
    let s: &str = "hi there";
    display(s);
}

但是,如果您将display功能更改为

fn display(x: &Display)

它出现以下错误:

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

display(s)更改为display(&s)它再次有效。

这里发生了什么?显然类型是&str,但当&Display是输入参数时,它不会识别出来。

注意:&34也可以作为参数使用。这是因为Display实际上是为&str实现的,而不是str

3 个答案:

答案 0 :(得分:6)

您正在请求将&str强制转换为&Display(对特征对象的引用),这似乎有意义,因为类型str实现了Display。< / p>

然而,从Rust 1.9开始(当前没有更改此计划),如果类型&T为“{&Trait,则TSized只能转换为特征对象。 {1}}”。

原因是实施。像&Display这样的特征对象由两个字段组成,一个指向数据的指针,以及一个指向特征方法表(vtable)的指针。此表示仅适用于其引用为“thin”的值,这些值恰好是类型where T: Sized&str是一个“胖”引用,它有一个指针和一个长度,因此str不能是特征对象的数据。

  

为什么显示器(&amp; s)有效?我想这是对“肥胖”参考的引用?

是的,确切地说。 &&str是一个“瘦”引用,指向具有&str值的变量。所以它可以转换为&Display

答案 1 :(得分:5)

(推荐我对主要答案的编辑)

当您编写fn display(x: &Display)时,该函数会通过解除引用来获取可以强制转换为trait object的值。 Rust函数也需要在编译时知道参数x的值大小。

&34&u32类型)被取消引用并强制转换为特质对象时,它变为u32并且可以确定其大小。

取消引用&str时,它变为str并且无法确定其大小,因为字符串的长度可以是任何值。

&添加到&str&&str),将其取消引用回&str,这是一个指针,可以确定其大小。我相信这就是编译器只在您的代码中接受display(&s)的原因。

答案 2 :(得分:1)

  

通过将显示更改为显示(&amp; s),它再次有效。

这一切都归结为&str: Display (+ Sized)str: !Display(这只是一种表示法)

  • display(s)预计s: &Display,=&gt; &str: &Display这是假的。
  • display(&s)期待&s: &Display =&gt; &(&str) : &Display&str: Display