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

为何结构体中可变引用可获取但自有String无法移出?

为什么获取可变引用&mut String合法,但移出自有String会报错?

我定义了一个包含可变引用&'a mut String和自有String的结构体S,尝试为其实现getx和gety两个获取方法。奇怪的是getx可以编译通过,但gety却报错。既然&mut String和String都未实现Copy trait,为什么编译器允许获取&mut String却不允许移出String?

代码示例

struct S<'a> {
    x: &'a mut String,
    y: String,
}
impl<'a> S<'a> {
    fn getx(&mut self) -> &mut String {
        self.x // Ok
    }
    fn gety(&mut self) -> String {
        self.y // Err
    }
}

错误信息

error[E0507]: cannot move out of self.y which is behind a mutable reference
move occurs because self.y has type String, which does not implement the Copy trait

核心原因:所有权与引用的本质差异

虽然&mut String和String都没有Copy trait,但两者的所有权属性完全不同:

  • getx方法:返回可变引用,未转移所有权
    self.x是可变引用类型&'a mut String,返回它时本质是复制了引用本身——引用类型(包括&mut)默认实现了Copy trait,所以这个操作是合法的。你只是拷贝了指向原字符串的可变引用,原结构体S中的x依然持有该引用,没有任何所有权转移,结构体的完整性也不受影响。

  • gety方法:移出自有String破坏结构体完整性
    self.y是S拥有所有权的String,直接返回self.y属于所有权转移(move)。但此时self是通过&mut self传递的可变引用,意味着调用方法后self实例依然存在——但它的y字段已被移走,结构体变成不完整状态,这违反了Rust的内存安全规则,因此编译器报错。

解决gety报错的可行方案

根据需求不同,可以选择以下方式:

  1. 转移结构体所有权:让方法接收self而非&mut self,这样整个结构体的所有权被转移,移出y后结构体不再被使用,符合规则:
    fn gety(self) -> String {
        self.y // Ok
    }
    
  2. 返回引用:只提供y的引用,不转移所有权:
    fn gety(&self) -> &String {
        &self.y // Ok
    }
    
  3. 克隆字符串:返回y的副本,适用于可以接受性能开销的场景:
    fn gety(&self) -> String {
        self.y.clone() // Ok
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:21:11