Please enable Javascript to view the contents

[Rust 基础知识]所有权与移动语义

 ·  ☕ 2 分钟

前言

    本文以最短篇幅概述 Rust 所有权和移动语义的基础知识点。之后几篇都会是所有权和生命周期的文章,这里先把基础的点整理一下。

想解决的问题

    思考以下场景:

1
2
Foo *p = new_object("args"); // create ptr
use_object(p); // use ptr

在不点进 use_object 前提下我们其实无从知道它对指针 p 到底做了什么,这就带来了很大的安全风险。为了缓解这种现象,一种目前应用广泛的方式就是使用“智能指针”。而 Rust 更进一步,将所有权的理念融入语言之中。

一般在讨论 Rust 的所有权时需要知道:

  • Rust 中每个值都有一个变量作为所有者
  • 每个值在同一时间只能有一个管理者
  • 当变量离开作用域时它的值也会被销毁

一个最简单的例子:

1
2
3
4
5
6
7
8
fn main() {
    let s = String::from("asd");

    let s2 = s;

    println!("{}", s2);
    //println!("{}", s); error!!
}

在 s 将所有权转移到 s2 以后我们再使用 s 就是非法的。如果想要 s 和 s2 都有效一种方式是显式进行克隆操作:

1
2
3
4
5
6
7
8
fn main() {
    let s = String::from("asd");

    let s2 = s.clone();

    println!("{}", s2);
    println!("{}", s);
}

移动语义

    在 Rust 中赋值语句,函数调用,函数返回都可能发生所有权转移。而所有权转移也是所有类型的默认语义(之前的文章提过可以通过 Copy trait 改变)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn create() -> String {
    let s = String::from("asd");
    s
}

fn consume(s: String) {
    println!("{}", s);
}

fn main() {
    let s2 = create();
    consume(s2);
}

上例中 String 的所有权从 create 内部转移到 main 然后又移入 consume 内部。这个所有权转移的过程我们可以简单的理解成 memcpy。不过需要注意的是理解成 memcpy 并不代表它真的是按 memcpy 执行的,编译器会在不改变代码语义的前提下帮我们做优化,所以不用纠结这个点。

Box

    Box 是 Rust 中的一种常用指针类型,表示“具有所有权的指针”:

1
2
3
4
5
6
7
8
struct T {
    index: i32,
}

fn main() {
    let tp = Box::new(T { index: 1 });
    println!("{}", tp.index);
}

在 Rust 中,所有的变量在使用前必须要合理初始化,这也意味着 Box<T> 一定是指向某个具体对象的。如果我们想要一个可能为空的指针,可以套个Option Option<Box<T>>;

总结

    作为 Rust 中最为重要的内容之一,这块的内容肯定很多,由于水平和时间限制只能挑一些我还能理解的写出来,等积累到一定程度再写一些更有深度的东西。

分享

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