Rust 第四节 - 认识所有权

91 阅读2分钟

4 认识所有权

4.1 所有权

当我们对一个没有实现可Copy特征的数据进行移动时,此时就发生了所有权的转移,例如:

let x = String::new();
let y = x; // 所有权发生了移动,此时我们再去打印x的值,会发生错误
println!("{}", x); // 报错

let basic: &str = "hello world";
let copy_basic: &str = basic;
println!("{}", basic); // 可以正常打印出来

还有什么情况会发生所有权的移动呢?当我们向函数传参时,也会发生,传参的过程就相当于声明了一个隐式的变量。例如:

let mut str: String = String::new();
str.push_str("hello");
fn calc_len(x: String) -> usize {
    return x.len();
}
let len: usize = calc_len(str); 
println!("{}", len);
println!("{}", str); // 报错,所有权转移到了函数内部,并且在函数执行完毕之后就被销毁

那么哪些数据是可Copy的呢?现在我们把所有默认具有该特征的数据类型列出来:

  • 所有的标量数据类型
    • 整数
    • 浮点数
    • 字符串字面量
    • 布尔值
  • (只包含标量数据类型的)元祖

4.2 引用和借用

那么当我想要传入函数(所有权力的例子)后,不失去所有权呢? 此时,我们就需要引入引用这个概念了。

我们想要引用一个数据时,需要在变量名前面加上&,这个时候我们可以调用它内部的一些函数,例如:

let mut str: String = String::from("hello");
fn calc_len(x: &String) -> usize {
    return x.len();
}
let len = calc_len(&str);
println!("{}", len);
println!("{}", str); // 报错,所有权转移到了函数内部,并且在函数执行完毕之后就被销毁

那如果我想对该变量进行修改呢?很简单,我么可以直接在&加上mut属性。例如:

let mut str: String = String::from("hello");
fn add_string(x: &mut String) {
    x.push_str(", world")
}

add_string(&mut str);
println!("{}", str);

4.3 切片

当我们想获取字符串(数组)的其中某一段的时候,这个时候我们就需要使用到切片的功能,例如:

let str: String = String::from("hello");
let x = &str[1..3];
println!("{}", x) // "el"

其中对于[1..3]我们可以理解为

  • 首位数为起始索引(包含),末位数为结束索引(不包含)
  • 当首位数没有的时候,默认为0,例如: [..3]
  • 当末位数没有的时候,默认为最后一个索引,例如: [1..]
  • 首位和末位都没有的时候,默认为整个字符串(数组)