Rust的所有权与可变性

Rust与其他语言的比较

特性

所有权

在Rust中,若声明有类似于Java或C++中的引用传递类型概念的变量,存在相同作用域下将地址赋值给另一个变量,则该变量的所有权将发生转移,原先的变量将不可访问

直接转移
/* Error: 进行类似于其他语言中的引用赋值,地址被新的变量获取,则会丧失所有权。 */
fn test2() {
    let a:Vec<i32> = Vec::new();
    a.push(1);
    let b = a; //将a的所有权转移给b
    println!("{}", a[0]); // 试图访问已丧失所有权的变量a
}

间接转移
/* Error: _v变量的地址被赋值给了change函数实参v,所有权已转移 */
fn test3() {
    let _v:Vec<i32> = Vec::new();
    _v.push(1);
    /* change函数得到了传递过来的Vec实例的所有权 */
    let change = |v:Vec<i32>| -> () {
        return;
    };
    change(_v);
    println!("{}", _v[0]); // 试图访问已丧失所有权的变量_v
}

引用、借用

在Rust中,由于有所有权的特性,若想用另一个变量去读取其值进行一些操作,而又不会丢失其所有权,可以使用引用特性,使用方式是将&加在变量名前。

事实上这样的场景十分常见。

如,现在有一个let nums:Vec<i32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].to_vec();,我们需要分别获取它们累加、累乘的结果。为了不丢失所有权,直接使用nums变量进行迭代获取结果显然是可行的,但并不优雅。我们可以分别实现累加、累成的函数进行操作。

这样的函数签名大概是这样的形式fn sum(arr: Vec<i32>)->i32fn mult(arr: Vec<i32>)->i32

但这会引发一个问题:间接转移test3代码段即存在这样的问题。当_v变量作为实参传入change函数时,_v的所有权就已经被转移到了change函数的形参v中,这意味着change一旦执行,_v则已丧失所有权,不可访问。

而这样的情况函数签名若是以fn sum(arr: Vec<i32>)fn mult(arr: Vec<i32>)的形式,那么意味着我们至多只能执行其中的一个sum或是mult,因为nums的所有权会在执行他们的其中一个时就已经转移丢失了。

所以为了保持其原有的所有权,我们需要有一种借用它的方式,这样的方式就是引用。针对累加、累乘,我们就可以写出这样的代码。

fn sum(arr: &Vec<i32>) ->i32 {
    let mut ans = 0;
    for n in arr.iter() {
        ans += n;
    }
    ans
}
fn mult(arr: &Vec<i32>) ->i32 {
    let mut ans = 1;
    for n in arr.iter() {
        ans *= n;
    }
    ans
}
let nums:Vec<i32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].to_vec();
let ans1 = sum(&nums); // 通过引用传递nums,保证nums不会丢失所有权,下同
let ans2 = mult(&nums);
println!("sum:{} mult:{}", ans1, ans2);
}

可变性与不可变性

Rust的let关键字自带const(不可变)性质,但与JavaScript、C++的const关键字带来的效果略有差异。在JavaScript、C++以修饰的const的变量,只为了确保其变量所指向堆区的地址是否发生变化,而不关心其地址指向堆中的内存区域的数据是否有所改变。

TypeScript中,以下代码段是合法的。

const array: Array<int> = []; // 声明一个名为array,int类型的数组
array.push(1); // 为array添加一个元素1

C++中,以下代码段是合法的。

const vector<int> array = vector<int>(); // 声明一个名为array,int类型的数组
array.push_back(1); // 为array添加一个元素1

而Rust不是这样的,任何变量,没有经过mut关键字的修饰,无论是栈中的内存数据还是堆区的内存数据,都是不可改变的。

/* Error: cannot borrow `array` as mutable, as it is not declared as mutable */
let array:Vec<i32> = Vec::new(); // 声明一个名为
array.push(1); // 尝试为array添加一个元素1,不可行

而如果想要为其添加元素,则必须使用mut关键字修饰。

/* 与javascript的const不同,Rust若不指定mut,则无法更改容器内的数据,这里的数据修改权不仅限于栈空间,更像是变量的可写权限? */
fn test5() {
    let mut _v:Vec<i32> = Vec::new();
    _v.push(1); // 直接添加
    /* change函数得到了传递过来的Vec实例的借用权 */
    let change = |v:& mut Vec<i32>| -> () {
        v.push(3);
        return;
    };
    change(&mut _v);
    println!("{}", _v[1]); // 可以成功获取change函数添加的元素3
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值