rust学习------[day2]理解ownership的特性

文章目录

Ownership

变量和数据的交互方式:move

普通变量的赋值

fn main() {
    let x = 5;
    let y = x;
}

第一句将5与变量x绑定,第二句是创建了一个x的值的副本,并将该值与变量y绑定

String类型变量的赋值

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
}

在rust中一个String类型由三部分组成:

  • 指向保存字符串内容的内存(这块内存在堆上)的指针
  • 长度
  • 容量

所以,上面的代码在rust中的处理可能有以下情况

  • 堆上的字符串内容并没有复制,仅复制栈上的变量,然后将s2的指针也指向堆上的字符串内容

    rust学习------[day2]理解ownership的特性

  • 堆和栈的内容都进行复制

    rust学习------[day2]理解ownership的特性

    这两种做法都有很大的缺点,方法一在变量失效的时候会多次释放内存,导致出错。方法二在字符串很大的时候程序的执行效率很差。所以rust采用的是下面的方式

  • 在方案一的基础上,s2复制完后,就将s1视为失效,s1超出范围之后不释放内存

    rust学习------[day2]理解ownership的特性

变量和数据的交互方式:clone

上面提到的move型的操作是不会对数据进行深拷贝,仅仅拷贝变量然后移交控制权。接下来介绍的clone型操作方式是会对数据进行深拷贝的

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();

    println!("s1 = {}, s2 = {}", s1, s2);
}

这段代码的执行就如方法二所示

栈上的数据

在复制时都是深拷贝。原因是:诸如在编译时具有已知大小的整数之类的类型完全存储在堆栈中,因此可以快速制作实际值的副本。

rust中可以给类型实现Copy trait,这样我们新实现的类型就可以放置在栈空间中。但是我们不能给已经实现了drop trait的类型再实现Copy trait。

不需要分配操作的类型都可以实现Copy trait。

以下是一些具有Copy trait的类型:

  • 所有的整型,类似u32
  • 布尔型
  • 所有的浮点型,类似f64
  • 字符类型,char
  • Tuples(元组中的类型只包含具有Copy trait的类型)

Ownership和函数

给函数传值类似于赋值操作,举个例子

fn main() {
    let s = String::from("hello");  // s comes into scope

    takes_ownership(s);             // s's value moves into the function...
                                    // ... and so is no longer valid here

    let x = 5;                      // x comes into scope

    makes_copy(x);                  // x would move into the function,
                                    // but i32 is Copy, so it's okay to still
                                    // use x afterward

} // Here, x goes out of scope, then s. But because s's value was moved, nothing
  // special happens.

fn takes_ownership(some_string: String) { // some_string comes into scope
    println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
  // memory is freed.

fn makes_copy(some_integer: i32) { // some_integer comes into scope
    println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.

当将s传入take_ownership函数之后,在使用变量s就会出错

返回值和Scope

直接举例

fn main() {
    let s1 = gives_ownership();         // gives_ownership moves its return
                                        // value into s1

    let s2 = String::from("hello");     // s2 comes into scope

    let s3 = takes_and_gives_back(s2);  // s2 is moved into
                                        // takes_and_gives_back, which also
                                        // moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
  // moved, so nothing happens. s1 goes out of scope and is dropped.

fn gives_ownership() -> String {             // gives_ownership will move its
                                             // return value into the function
                                             // that calls it

    let some_string = String::from("hello"); // some_string comes into scope

    some_string                              // some_string is returned and
                                             // moves out to the calling
                                             // function
}

// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
                                                      // scope

    a_string  // a_string is returned and moves out to the calling function
}

如果我们希望将变量传入函数之后继续使用该变量,我们需要将值以返回值的形式在返回给变量。如果想返回多个值,可以以元组的形式将值返回

上一篇:$NOIP\ 2018\ Day2$ 模拟考试 题解报告


下一篇:【2018暑假集训模拟一】Day2题解