You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

根据Rust标准库,何时可将引用视为「失效」?

Rust可变引用的「失效」到底怎么算?

先把问题说透

你纠结的点其实是:官方文档用mem::transmute实现split_at时,说原可变引用slice在某行之后不再用就视为「失效」,但这个说法太模糊——什么时候可变引用算「失效」?要是之后还要用原引用(比如你写的foo函数最后又调用bar(slice)),这逻辑不就矛盾了?

先纠正一个误解:没有「失效」,只有「暂时锁死」和「彻底没用」

Rust官方根本没定义「失效」这个词,这是文档为了方便理解搞的简化说法。本质上,这都是Rust借用规则在起作用,核心就是同一时间,同一块内存只能有一个能干活的可变引用。

1. 官方示例里的「失效」是什么意思

看split_at_stdlib的实现逻辑:

fn split_at_stdlib<T>(slice: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
    let ptr = slice.as_mut_ptr();
    let len = slice.len();
    unsafe {
        let ret = (
            std::mem::transmute(&mut ptr[0..mid]),
            std::mem::transmute(&mut ptr[mid..len]),
        );
        // 文档说的「slice在此之后不再被使用,视为失效」
        ret
    }
}

这里的「失效」其实是说:原引用slice从生成ret到函数返回这段时间里,根本没被任何代码碰过。虽然它还存在,但因为没被使用,借用检查器就不会把它当成「活跃的可变引用」,所以和返回的两个切片不会冲突——毕竟规则管的是「活跃的」可变引用,你放着不用的引用,编译器不管。

2. 你写的foo函数为什么合法

再看这个场景:

fn bar<T>(slice: &mut [T]) { ... }
fn foo<T>(slice: &mut [T]) {
    {
        let (front, back) = split_at_stdlib(slice, 5);
        bar(front);
        bar(back);
    } // 这里是关键:front和back的作用域结束了
    bar(slice); // 原引用又能用来干活了
}

这里完全符合规则:

  • 当你在内部代码块里拿到front和back时,原引用slice就被暂时锁死了——你要是在代码块里写bar(slice),编译器直接给你报错,说你同时用了多个可变引用。
  • 等代码块结束,front和back就彻底没用了(它们的存活时间到了),原引用slice的锁就解开了,这时候再用它就完全没问题。

怎么判断可变引用能不能用?记住两个关键点

别纠结「失效」这个词,换成「能不能被访问」来判断:

  • 能被访问的可变引用(活跃):当前代码里还能调用、修改它,这时候绝对不能有其他指向同一块内存的活跃可变引用。
  • 不能被访问的可变引用(不活跃):要么是被派生的可变引用锁死了(比如上面的slice在代码块里的状态),要么是已经超出了它的作用域(比如函数里的局部引用,函数返回后就彻底没用了)。

简单说:

  1. 看作用域:如果引用已经走出它的代码块/函数,那就是彻底失效,再也用不了了。
  2. 看借用关系:如果从一个可变引用变出了新的可变引用,原引用在新引用活着的时候就被锁死,不能碰;等新引用死了,原引用才解锁。

最后总结一下

官方文档的「失效」就是个简化说法,本质还是Rust的核心规则:同一时间,同一块内存只能有一个能干活的可变引用。只要你别在派生引用还活着的时候去碰原引用,就不会有问题——哪怕原引用之后还要用,只要等派生引用死了再用就行。

内容的提问来源于stack exchange,提问作者ajp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 00:17:22