阅读 112

Rust中的函数参数可变与不可变

假设有以下结构体:

#[derive(Debug)] struct A {      x: i32, } 复制代码

若要设计一函数,可以改变结构体中成员x的值:

fn add(a: A, b: A) {     a.x += b.x; //编译不通过 }     复制代码

编译结果如下:

    | 137 |     fn add(a: A, b: A) {     |            - help: consider changing this to be mutable: `mut a` 138 |         a.x += b.x;     |         ^^^^^^^^^^ cannot assign 复制代码

需要给参数加上mut:

fn add_mut(mut a: A, b: A) {     a.x += 1; //不但可以修改成员值     a = A { x: 1 }; //还可以修改a本身     a.x += 2; //重新赋值后仍然可以修改新值成员变量 } let a = A { x: 1 }; let b = A { x: 2 }; add_mut(a, b); 复制代码

如果希望只修改成员x的值:

fn add_ref_mut<'s>(a: &'s mut A, b: &'s mut A) {     a.x += b.x;     a = b; // 修改本身则编译不通过 } 复制代码

编译不通过:

    | 153 |     fn add_ref_mut<'s>(a: &'s mut A, b: &'s mut A) {     |                        - help: consider making this binding mutable: `mut a` 154 |         a.x += b.x; 155 |         a = b; // borken     |         ^^^^^ cannot assign to immutable argument 复制代码

同时,还会有一个前置条件,就是传入的参数必须为mut:

//注:第二个参数 b 没有修改,其实可以去掉mut,但这里为了一致性就保留下来了。 fn add_ref_mut<'s>(a: &'s mut A, b: &'s mut A) {     a.x += b.x; } let a = A { x: 1 }; let b = A { x: 2 }; add_ref_mut(&mut a, &mut b);// 不通过 复制代码

错误为:

   --> src/controller/game_service.rs:184:21     | 182 |         let a = A { x: 1 };     |             - help: consider changing this to be mutable: `mut a` 183 |         let b = A { x: 2 }; 184 |         add_ref_mut(&mut a, &mut b);     |                     ^^^^^^ cannot borrow as mutable 复制代码

修改为:

let mut a = A { x: 1 }; let mut b = A { x: 2 }; add_ref_mut(&mut a, &mut b);// 通过 复制代码

也就是说,使用mut引用,前置条件是传入参数必须声明为mut。

也可以mut加 &mut,这样所有权就不会转移,又能修改变量本身:

fn add_mut_ref<'s>(mut a: &'s mut A, b: &'s mut A) {     a.x += 1;     a = b; } 复制代码

总结几种参数写法:

参数变量可修改数据可修改所有权转移前置mut
a: ANNY
mut a: AYYYN
a: &ANNN
a : &mut ANYNY
mut a : &mut AYYNY

注:这里的所有权转移,是基于数据类型没有Copy与Clone特性的前提下的,否则就是Copy了。

何时用mut何时用&mut?

假如结构体有Copy特性,会如何?

#[derive(Copy, Clone, Debug)] struct B {     x: i32, } fn add_copy(mut a: B, x: i32) {     a.x += x;     println!("in side {:?}", a); } let a = B { x: 0 }; add_copy(a, 1); // 这里所有权没有转移,而是复制 add_copy(a, 3); // 这里所有权没有转移,而是复制 let mut b = a; // 这里所有权没有转移,而是复制 b.x = 2; println!("what is a?:{:?}", a); 复制代码

运行结果是:

in side B { x: 1 } in side B { x: 3 } what is a?:B { x: 0 } 复制代码

可见,如果对象有Copy特性,所有权就不会转移,直接复制了。

所以,如果要对数据进行修改,最可靠的方式还是&mut

fn add_copy_mut(a: &mut B, x: i32) {     a.x += x;     println!("in side {:?}", a); } let a = B { x: 0 }; let mut a = a; // 这里也是复制,通过rust的变量遮蔽(variable shadowing),把原来的a给覆盖掉 add_copy_mut(&mut a, 5); println!("what is a now?:{:?}", a); 复制代码

变量终于修改成功:

in side B { x: 5 } what is a now?:B { x: 5 }


作者:govo
链接:https://juejin.cn/post/7018076395741904903


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐