为什么 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
.
下面的代码可以正常编译和运行:
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
.