LearningOS/rcore_step_by_step

代码中为何类型不匹配,但能编译通过?

Closed this issue · 2 comments

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) 这行的实参类型与函数的形参类型不一致还能编译通过?

隐式类型转换,Deref Trait。

因为 &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 函数的定义了。