Please enable Javascript to view the contents

[Rust 基础知识]借用与借用规则

 ·  ☕ 2 分钟

前言

    本文以最短篇幅概括借用和借用规则的相关知识点。

借用

    在 Rust 中,变量除了可以直接进行所有权转移,还可以借用。借用分为两种:只读借用(&),和读写借用(&mut)。所谓的借用和指针更多的是语义上的区别,标记该借用来的指针对内存没有“所有权”。“借用”概念是在编译阶段的静态检查中起作用。

需要弄清的是 mut 在不同场景下的意义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
struct T {
    index: i32,
}

fn test_fn(param1: &T, param2: &mut T, param3: &T) { // param2 参数需要可变引用
    if param3.index > 0 {
        param2.index = param1.index;
    }
}

fn main() {
    let tp = T { index: 1 };
    let mut tp2 = T { index: 0 }; // tp2 是可变的
    let mut tp3 = T { index: 3 }; // tp3 是可变的

    test_fn(&tp, &mut tp2, &tp3); // 读写借用可变变量 tp2  只读借用可变变量 tp3 
}

当修饰 Self 时:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct T {
    index: i32,
}

impl T {
    fn test_self_fn(&self) {
        println!("test self fn");
    }

    fn test_mut_self_fn(&mut self) {
        println!("test mut self fn");
    }
}

fn main() {
    let tp = T { index: 1 };
    let mut tp2 = T { index: 0 };

    tp.test_self_fn();
    //tp.test_mut_self_fn(); // 只有被 mut 修饰的变量才能调用 &mut self 的函数
    tp2.test_self_fn();
    tp2.test_mut_self_fn();
}

在 Rust 中还有一种叫做切片(Slice)的类型,利用它能够引用集合中的一段连续序列,而不是整个集合。

1
2
3
4
5
6
7
fn main() {
    let str1 = String::from("abcdefghijklmn");
    let c1 = [1, 2, 3, 4, 5, 6];

    println!("{}", &str1[..3]);
    println!("{:?}", &c1[1..2]);
}

需要注意字符串切片是按 byte 分的,以后再单开文章讲 utf8 字符串的处理。

借用规则

    既然整出了个借用的概念,那么肯定就有对应的约束规则。

第一点:引用必须是有效的。最经典的反面例子就是返回局部变量的引用。

1
2
3
4
fn dangle() -> &String { 
    let s = String::from("hello"); 
    &s 
}

第二点:在同一时间只允许有一个可变引用或者多个只读引用。这里需要注意的是这里讲的是有效代码:

1
2
3
4
5
6
7
8
9
fn main() {
    let mut str1 = String::from("adasdsa");

    let str2 = &mut str1;
    let str3 = &str1;
    str1 += "adad";

    println!("{}", str1);
}

上例中的 str2 和 str3 从未使用过,所以只会报 warning。

早期 Rust 对借用的检查比较死板,引入 NLL (Non Lexical Lifetime)以后可以更精细的调节变量的作用范围,对于一些不会产生安全问题的写法放宽了限制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn main() {
    let mut data = vec!['a', 'b', 'c', 'd'];
    let slice = &mut data[..];
    for elem in slice {
        elem.make_ascii_uppercase();
    }

    data.push('c');

    println!("{:?}", data);
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn process_or_default() {
    let mut map = ...;
    let key = ...;
    match map.get_mut(&key) {
        Some(value) => process(value),    
        None => {                         
            map.insert(key, V::default());
        } 
    }
}
分享

saberuster
作者
saberuster
一个喜欢编程和折腾的追风少年