代码中为何类型不匹配,但能编译通过?
Closed this issue · 2 comments
chyyuu commented
fn main() {
let my_string = String::from("hello world");
let word = first_word(&my_string); //my_string的类型是&String,与first_word参数类型不一致
let my_string_literal = "hello world";
let word = first_word(&my_string_literal[..]);
let word = first_word(my_string_literal);
}
fn first_word(s: &str) -> &str { //参数类型是&str
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
Q:
为何 let word = first_word(&my_string)
这行的实参类型与函数的形参类型不一致还能编译通过?
jiegec commented
隐式类型转换,Deref Trait。
chyyuu commented
因为 &String 可以被 强转(coerced)成 &str。当first_word函数被调用时,Rust 使用了一个被称为 解引用强制多态(deref coercion)的技术,你可以将其理解为它把 &s2 变成了 &s2[..]。从而可以正确编译并运行。如:
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn hello(name: &str) {
println!("Hello, {}!", name);
}
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&m);
}
这里使用 &m 调用 hello 函数,其为 MyBox 值的引用。因为示例 在 MyBox 上实现了 Deref trait,Rust 可以通过 deref 调用将 &MyBox 变为 &String。标准库中提供了 String 上的 Deref 实现,其会返回字符串 slice,这可以在 Deref 的 API 文档中看到。Rust 再次调用 deref 将 &String 变为 &str,这就符合 hello 函数的定义了。