Rust语言从入门到精通系列 - Borrow和BorrowMut特征

3 分钟阅读

Rust 语言是一种系统级编程语言,它强调安全、速度和并发性。Rust 的内存管理机制是通过所有权系统实现的,这意味着每个值都有一个所有者,并且只能有一个所有者。当值超出其所有者的范围时,它将被释放。这种机制可以防止许多常见的内存错误,如空指针引用和野指针。

然而,有时候我们需要在不拥有值的情况下对其进行操作。Rust 提供了 borrow 和 borrow_mut 两个方法来实现这个目的。这两个方法允许我们借用值的所有权,而不是拥有它。这种方式可以使我们在不破坏所有权系统的前提下,进行一些特定的操作。

基础用法

Borrow

Borrow 方法用于借用一个值的不可变引用。这个方法的语法如下:

1
fn borrow(&self) -> &T

其中,&self表示当前值的引用,&T表示返回的借用值的类型。下面是一个使用 borrow 方法的示例:

1
2
3
4
5
fn main() {
    let v = vec![1, 2, 3];
    let r = v.borrow();
    println!("{:?}", r);
}

这个示例中,我们创建了一个包含三个元素的向量。然后,我们使用 borrow 方法来借用这个向量的不可变引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为[1, 2, 3]

BorrowMut

BorrowMut 方法用于借用一个值的可变引用。这个方法的语法如下:

1
fn borrow_mut(&mut self) -> &mut T

其中,&mut self表示当前值的可变引用,&mut T表示返回的借用值的类型。下面是一个使用 borrow_mut 方法的示例:

1
2
3
4
5
6
fn main() {
    let mut v = vec![1, 2, 3];
    let r = v.borrow_mut();
    r.push(4);
    println!("{:?}", v);
}

这个示例中,我们创建了一个包含三个元素的向量,并将其绑定到变量 v 上。然后,我们使用 borrow_mut 方法来借用这个向量的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 的 push 方法向向量中添加一个元素。最后,我们打印出 v 的值。输出结果为[1, 2, 3, 4]

借用一个字符串的不可变引用

1
2
3
4
5
fn main() {
    let s = String::from("hello");
    let r = s.borrow();
    println!("{}", r);
}

这个示例中,我们创建了一个包含字符串”hello”的字符串。然后,我们使用 borrow 方法来借用这个字符串的不可变引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为hello

借用一个字符串的可变引用

1
2
3
4
5
6
fn main() {
    let mut s = String::from("hello");
    let r = s.borrow_mut();
    r.push_str(", world!");
    println!("{}", s);
}

这个示例中,我们创建了一个包含字符串”hello”的字符串,并将其绑定到变量 s 上。然后,我们使用 borrow_mut 方法来借用这个字符串的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 的 push_str 方法向字符串中添加一个后缀。最后,我们打印出 s 的值。输出结果为hello, world!

借用一个数组的不可变引用

1
2
3
4
5
fn main() {
    let a = [1, 2, 3];
    let r = a.borrow();
    println!("{:?}", r);
}

这个示例中,我们创建了一个包含三个元素的数组。然后,我们使用 borrow 方法来借用这个数组的不可变引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为[1, 2, 3]

借用一个数组的可变引用

1
2
3
4
5
6
fn main() {
    let mut a = [1, 2, 3];
    let r = a.borrow_mut();
    r[1] = 4;
    println!("{:?}", a);
}

这个示例中,我们创建了一个包含三个元素的数组,并将其绑定到变量 a 上。然后,我们使用 borrow_mut 方法来借用这个数组的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 来修改数组中的一个元素。最后,我们打印出 a 的值。输出结果为[1, 4, 3]

借用一个结构体的不可变引用

1
2
3
4
5
6
7
8
9
10
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 2 };
    let r = &p;
    println!("{:?}", r);
}

这个示例中,我们创建了一个包含 x 和 y 两个字段的结构体 Point,并将其绑定到变量 p 上。然后,我们使用&符号来借用这个结构体的不可变引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为Point { x: 1, y: 2 }

借用一个结构体的可变引用

1
2
3
4
5
6
7
8
9
10
11
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let mut p = Point { x: 1, y: 2 };
    let r = &mut p;
    r.x = 3;
    println!("{:?}", p);
}

这个示例中,我们创建了一个包含 x 和 y 两个字段的结构体 Point,并将其绑定到变量 p 上。然后,我们使用&mut 符号来借用这个结构体的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 来修改结构体中的一个字段。最后,我们打印出 p 的值。输出结果为Point { x: 3, y: 2 }

进阶用法

借用一个值的引用

1
2
3
4
5
6
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let r = &v1;
    println!("{:?}", r);
}

这个示例中,我们创建了两个包含三个元素的向量 v1 和 v2。然后,我们使用&符号来借用 v1 的引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为[1, 2, 3]

借用一个值的可变引用的引用

1
2
3
4
5
6
7
fn main() {
    let mut v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let r = &mut &mut v1;
    (*r).push(4);
    println!("{:?}", v1);
}

这个示例中,我们创建了两个包含三个元素的向量 v1 和 v2,并将 v1 绑定到变量 v1 上。然后,我们使用&mut 符号来借用 v1 的可变引用的可变引用,并将其绑定到变量 r 上。接着,我们使用*r 来访问 v1,并向其添加一个元素。最后,我们打印出 v1 的值。输出结果为[1, 2, 3, 4]

借用一个值的不可变引用的可变引用

1
2
3
4
5
6
7
fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let r = &mut &v1;
    **r = vec![7, 8, 9];
    println!("{:?}", v1);
}

这个示例中,我们创建了两个包含三个元素的向量 v1 和 v2。然后,我们使用&符号来借用 v1 的不可变引用的可变引用,并将其绑定到变量 r 上。接着,我们使用**r 来访问 v1,并将其替换为一个新的向量。最后,我们打印出 v1 的值。输出结果为[7, 8, 9]

借用一个值的可变引用的不可变引用

1
2
3
4
5
6
7
fn main() {
    let mut v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let r = &v1.borrow_mut();
    r.push(4);
    println!("{:?}", v1);
}

这个示例中,我们创建了两个包含三个元素的向量 v1 和 v2,并将 v1 绑定到变量 v1 上。然后,我们使用 borrow_mut 方法来借用 v1 的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 的 push 方法向 v1 中添加一个元素。最后,我们打印出 v1 的值。输出结果为[1, 2, 3, 4]

最佳实践

在使用 borrow 和 borrow_mut 方法时,需要注意以下几点:

  1. 不要同时借用一个值的可变引用和不可变引用。这会导致编译器错误。

  2. 不要在可变引用的生命周期内使用不可变引用。这会导致编译器错误。

  3. 不要在不可变引用的生命周期内使用可变引用。这会导致编译器错误。

  4. 在使用 borrow 和 borrow_mut 方法时,应该尽量减少借用的范围和时间。这可以提高代码的可读性和可维护性。

下面是一个示例代码,展示了如何使用 borrow 和 borrow_mut 方法来操作一个向量:

1
2
3
4
5
6
7
8
9
10
11
fn main() {
    let mut v = vec![1, 2, 3];
    {
        let r = v.borrow_mut();
        r.push(4);
    }
    {
        let r = v.borrow();
        println!("{:?}", r);
    }
}

这个示例中,我们创建了一个包含三个元素的向量,并将其绑定到变量 v 上。然后,我们使用 borrow_mut 方法来借用这个向量的可变引用,并将其绑定到变量 r 上。接着,我们使用 r 的 push 方法向向量中添加一个元素。然后,我们使用 borrow 方法来借用这个向量的不可变引用,并将其绑定到变量 r 上。最后,我们打印出 r 的值。输出结果为[1, 2, 3, 4]

总结

borrow 和 borrow_mut 方法是 Rust 语言中非常重要的方法,它们允许我们在不拥有值的情况下对其进行操作。这种方式可以使我们在不破坏所有权系统的前提下,进行一些特定的操作。在使用 borrow 和 borrow_mut 方法时,需要注意借用的范围和时间,以及避免出现编译器错误。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com)

TinyZ Zzh

TinyZ Zzh

专注于高并发服务器、网络游戏相关(Java、PHP、Unity3D、Unreal Engine等)技术,热爱游戏事业, 正在努力实现自我价值当中。

评论

  点击开始评论...