返回文章列表

文章

关于Rust中的自动解引用

目录
  1. 在fill_vec函数中vec参数是&Vec<i32>类型,然后let mut vec = vec.clone(); vec.clone() 本质上是&Vec<i32> 的clone,为什么这里&Vec<i32> 的clone返回的却是一个Vec<i32>类型的数据? 这其实是Rust中自动解引用(auto-dereferencing)的一种语法糖,它让你可以更简洁地使用引用类型而无需手动写 * 运算符。这一特性主要体现在以下几个场景中:
  2. 🔑 Rust 自动解引用的几个核心场景
  3. ✅ 1. 方法调用(dot 语法)
  4. ✅ 2. 字段访问(如 .x)
  5. ✅ 3. 函数参数匹配
  6. ✅ 4. Deref 强制转换
  7. ✅ 5. 在比较和 assert 中
  8. 🧠 自动解引用只在某些场景触发:
  9. 📌 实现自动解引用的根本机制
  10. 你也可以自定义类型并通过实现 Deref 让它支持自动解引用行为。
  11. ✅ 小结

首先看下面这段代码

fn fill_vec(vec: &Vec<i32>) -> Vec<i32> {
    let mut vec = vec.clone();

    vec.push(88);

    vec
}
//使用fill_vec函数
mod tests {
    use super::*;

    // TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
    // fix the compiler error in the test.
    #[test]
    fn move_semantics2() {
        let vec0 = vec![22, 44, 66];

        let vec1 = fill_vec(&vec0);

        assert_eq!(vec0.clone(), [22, 44, 66]);
        assert_eq!(vec1, [22, 44, 66, 88]);
    }
}

fill_vec函数中vec参数是&Vec<i32>类型,然后let mut vec = vec.clone(); vec.clone() 本质上是&Vec<i32> 的clone,为什么这里&Vec<i32> 的clone返回的却是一个Vec<i32>类型的数据? 这其实是Rust中自动解引用(auto-dereferencing)的一种语法糖,它让你可以更简洁地使用引用类型而无需手动写 * 运算符。这一特性主要体现在以下几个场景中:#

🔑 Rust 自动解引用的几个核心场景#

✅ 1. 方法调用(dot 语法)#

这是最常见的自动解引用场景。 当你对一个引用调用方法时,Rust 会自动尝试解引用直到找到该方法。

let s = String::from("hello");
let len = s.len();         // 正常调用
let r = &s;
let len2 = r.len();        // 自动解引用为 (*r).len()

解释:

  • r.len() 实际会变成 (*r).len()
  • 如果 r 还是引用,Rust 会继续解引用直到找到方法。 Rust 会在以下这几步中查找方法:
  1. &T 上有没有这个方法?
  2. 如果没有,T 上有没有这个方法?
  3. 如果没有,继续解引用 T 直到找到。
  4. 如果找到了方法定义在某个 Deref 实现上(如 Rc<T>Box<T>),也会尝试调用。

✅ 2. 字段访问(如 .x#

struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
let rp = &p;

println!("{}", rp.x); // 自动解引用为 (*rp).x

✅ 3. 函数参数匹配#

如果你传入的类型是引用,而函数签名需要的是值(或反之),Rust 会自动添加 *& 来适配。

fn print_str(s: String) {
    println!("{}", s);
}

let s = String::from("hi");
let r = &s;
print_str(r.clone()); // ✅ OK,调用的是 clone() 后的 String

或者这个例子:

fn takes_str(s: &str) { println!("{}", s); }

let s = String::from("hi");
takes_str(&s);  // ✅ 自动从 String -> &str(Deref)

✅ 4. Deref 强制转换#

当你使用 Box<T>Rc<T>Arc<T>StringVec<T> 等智能指针时,Rust 自动调用 Deref trait 实现来解引用成目标类型。

use std::ops::Deref;

let x = Box::new(5);
let y = *x;  // 手动解引用
println!("{}", x + 1); // ❌ 加法不支持 Box<i32>
println!("{}", *x + 1); // ✅

更常见的例子:

fn greet(name: &str) {
    println!("Hello, {name}!");
}

let name = String::from("Alice");
greet(&name); // ✅ String 自动 Deref 到 &str

✅ 5. 在比较和 assert 中#

Rust 在 assert_eq! 等宏内部也会自动解引用进行值比较:

let a = [1, 2, 3];
let v = vec![1, 2, 3];

assert_eq!(a, *v);  // Vec<T> 解引用为 [T]

🧠 自动解引用只在某些场景触发:#

场景自动解引用?
方法调用 (.)✅ 是
字段访问 (.)✅ 是
函数调用参数匹配✅ 是
模式匹配 (match)❌ 否
显式赋值或操作符❌ 否

📌 实现自动解引用的根本机制#

Rust 借助 DerefDerefMut trait 实现了自动解引用功能:

use std::ops::Deref;

impl<T> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        // 实现细节...
    }
}

你也可以自定义类型并通过实现 Deref 让它支持自动解引用行为。#

✅ 小结#

场景示例自动解引用行为
方法调用r.len()会自动解引用直到找到方法
字段访问p.x自动解引用为 (*p).x
函数参数takes_str(&String)String 被 Deref 到 &str
Vec<T>[T]*vec自动 Deref 到 slice

如果你在写代码时遇到 .something() 能用但 *something.something() 却出错,很可能是 Rust 为你自动插入了解引用语义。 如需深入了解 DerefDerefMut 的高级用法,我也可以补充相关内容。