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

Why does Rust not recognize that a variable is a &str?

下面的代码可以正常编译和运行:

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 实施的吗?

(将我的编辑提升到主要答案)

当您编写 fn display(x: &Display) 时,该函数采用可以通过取消引用将其强制转换为 trait object 的值。此外,Rust 函数需要在编译时知道参数 x 的值大小。

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

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

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

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

这一切都归结为 &str: Display (+ Sized)str: !Display(这只是一个符号)

  • display(s) 期望 s: &Display, => &str: &Display 这是错误的。
  • display(&s) 期望 &s: &Display => &(&str) : &Display&str: Display
  • 相同

您要求将 &str 强制转换为 &Display(对 trait 对象的引用),这似乎是有道理的,因为类型 str 实现了 Display .

然而,从 Rust 1.9 开始(目前没有改变它的计划),如果类型 T&T&Trait,则只能转换为特征对象“Sized”。

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


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

是的,没错。 &&str 是指向具有 &str 值的变量的“瘦”引用。所以可以转换为&Display.