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

Rust中不可变变量放入Box后可修改?所有权转移相关疑问

问题解析:不可变变量赋值后可修改的原因

先看你提供的代码:

let mut a = Box::new("123".to_string());
let b = Box::new(&mut a);

b.push('4');

assert_eq!("1234", b.as_str());

// lets see the types:
// let x001: Box<&mut Box<String>> = b;
// let x001:&mut Box<String> = *b;
// let x001:Box<String> = **b;
// let x001:String = ***b;
// let x001:str = ****b;

let c = Box::new("456".to_string());

**b = c;

b.push('9');
(*b).push('9');
(**b).push('9');
(***b).push('9');
// (****b).push('9'); // no method named `push` found for type `str` in the current scope

// c.push( 'a'); // cannot mutate immutable variable `c`

assert_eq!("4569999", b.as_str());

***b = "abcd".to_string();

b.push('9');

assert_eq!("abcd9", b.as_str());

你疑惑的点是:不可变的c赋值给**b后,却能通过b修改内容,是不是所有权转移导致的?会不会所有不可变变量都能这么改?

核心解释:绑定的可变性 ≠ 值的可变性

Rust里的变量可变性是绑定的属性,不是值本身的属性:

  1. let c = Box::new("456".to_string()); 是不可变绑定,意味着你不能修改c这个变量本身——比如不能给c重新赋值,也不能通过c获取内部String的可变引用(所以直接调用c.push('a')会报错)。但c持有的Box<String>里的String本身是可变类型,只是被不可变绑定限制了访问方式。

  2. **b = c; 这一步确实发生了所有权转移:

    • b的类型是Box<&mut Box<String>>,解引用两次后**b是Box<String>类型,这里的赋值是把c绑定的Box<String>的所有权直接转移给**b指向的位置(也就是原来a的内存位置)。
    • 转移完成后,c就不再拥有这个Box<String>的所有权了——这才是c.push('a')报错的真正原因(不是单纯因为不可变,而是c已经变成无效的空绑定了)。
  3. 为什么能通过b修改内容?

    • b内部持有一个&mut Box<String>类型的可变引用,通过解引用链(b → *b → **b → ***b)可以最终获取到String的可变引用,自然就能调用push修改内容。
    • 当c的所有权转移到**b后,这个Box<String>就处于b的可变引用链覆盖范围内,所以可以被修改。

结论:不是所有不可变变量都能被修改

这不是漏洞,而是Rust所有权和可变性规则的正常表现:

  • 不可变绑定只是限制了通过该绑定对值的修改,一旦值的所有权转移到其他位置,只要新位置有可变访问权限,就可以修改值。
  • 如果c的所有权没有被转移(比如c是Copy类型,赋值时只会复制而不是转移),那c依然持有原有的值,你还是不能通过c修改它,但可以修改转移后的副本(如果副本有可变权限的话)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 07:27:44