Rust变量遮蔽(shadowing)场景下为何未声明mut也无报错?
为什么未声明mut的遮蔽变量接收返回值不会触发编译错误
这是Rust变量遮蔽规则和绑定可变性规则共同决定的:
- 每次使用
let关键字声明同名变量时,本质是在当前作用域创建了全新的变量绑定,和之前同名的旧绑定是否可变、绑定了什么值没有任何关联。旧的mename绑定在所有权被move走之后就会被编译器废弃,和新的mename绑定是完全独立的两个实体。 - Rust的
mut是变量绑定的属性,不是值的属性,也不是变量名的属性。不可变绑定的限制是:绑定完成初始化之后,不能通过这个绑定修改它指向的值。而你写let mename = xxx的时候,等号的赋值是新绑定的初始化流程,不属于「修改已有绑定的值」,自然不会触发不可变绑定的修改报错。 - 如果你去掉赋值前的
let,直接写mename = displayswithhere(mename),这才是尝试修改已有不可变绑定的值,会直接触发编译错误。 - 另外补充:
displayswithhere的调用流程只是把旧mename持有的String所有权move进函数,函数执行完又把同一个String的所有权返回给新的mename绑定,整个过程没有修改任何不可变绑定指向的值,完全符合所有权规则。
这段代码是否存在bug
这段代码可以正常编译运行,输出结果和代码书写的逻辑一致,没有功能性的编译错误或运行时bug,但存在不必要的冗余写法,属于不好的实践:
- 第一处冗余是
displayswithhere函数的设计:这个函数仅需要读取字符串内容做打印,完全不需要获取String的所有权,接收&str引用即可,现在把所有权传来传去再原封不动返回,属于无意义的所有权流转,增加了不必要的逻辑开销。 - 第二处是无意义的变量遮蔽:三次
let mename的遮蔽写法,运行效果确实和初始就声明let mut mename后原地修改一致,但这种写法会误导代码阅读者,让人误以为几次赋值的mename是语义不同的新变量,实际全程都是在操作同一个字符串内容,平白增加了代码理解成本。 - 补充说明:
addshere函数参数里的mut astring是完全合法的写法——当值的所有权转移到函数内部后,函数可以自行决定参数绑定是否可变,和调用方传值的绑定是不是可变没有任何关系,这部分符合Rust所有权规则,没有问题。
内容的提问来源于stack exchange,提问作者StealthyPanda
相关产品推荐
相关产品推荐

