美文网首页
Rust学习笔记之Ownership

Rust学习笔记之Ownership

作者: 天之見證 | 来源:发表于2022-08-24 18:39 被阅读0次

    Rust使用ownership系统来管理内存,编译器会检查这些ownership系统的规则,一旦违反这些规则,则编译不通过

    0. 堆和栈

    编译期大小可知的数据,放在栈上

    编译器大小不定,数据放在堆上,对应的指针放在栈上

    1. Ownership的规则

    1. Rust中每个值都有一个owner

    2. 任何时间有且仅有一个owner

    3. owner离开作用域之后,对应的值将会被删掉

    2. 作用域

    Rust中变量离开作用域之后,会被调用drop方法

    2.1 变量作用域

    fn main() {
        {                      // s is not valid here, it’s not yet declared
            let s = "hello";   // s is valid from this point forward
    
            // do stuff with s
        }                      // this scope is now over, and s is no longer valid
    }
    

    上面的代码注释详细给出了对应的变量作用域

    2.2 heap对象的赋值操作

    图片.png

    下面的赋值操作有个问题是,当s1,s2都离开作用域的时候,其对应的同一块内存会被释放两次,造成错误

    let s1 = String::from("hello");
    let s2 = s1;  // s1赋值完之后,就不再有用了
    
    println!("{}, world!", s1);  // 到这一行没法编译
    

    2.2.1 move != 浅拷贝

    由于在Rust中,赋值完之后,并且失效了前一个变量,则不能称其为浅拷贝,而称其为move

    图片.png

    2.2.2 clone=深拷贝

    由于以上的原因,Rust不会主动去深拷贝数据,则需要我们显式的声明,见下面的代码:

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

    2.3 stack对象的赋值操作

    fn main() {
        let x = 5;
        let y = x;
    
        println!("x = {}, y = {}", x, y);
    }
    

    由于上述变量在编译器大小可知,则都是存储在栈上,没有深拷贝和浅拷贝的区别,可以看作是深拷贝

    2.4 Ownership与函数

    在Rust中,将一个值传递给函数,类似于将其赋值给一个变量

    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.
    

    明白了上面heap对象和stack对象的赋值操作,上述代码可以看出:

    1. s在之后就无法再用了,因为当其被传入函数的时候,就已经不是它自己了,除非是把自己clone一份

    2. x还可以再用,因为是一个深拷贝

    2.5 函数返回值

    赋值情况也是类似的道理

    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 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("yours"); // some_string comes into scope
    
        some_string                              // some_string is returned and
                                                 // moves out to the calling
                                                 // function
    }
    
    // This function takes a String and returns 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
    }
    

    如果我们想再拿回之前传入的值,在没有references的情况下,只能再返回出来

    fn main() {
        let s1 = String::from("hello");
    
        let (s2, len) = calculate_length(s1);
    
        println!("The length of '{}' is {}.", s2, len);
    }
    
    fn calculate_length(s: String) -> (String, usize) {
        let length = s.len(); // len() returns the length of a String
    
        (s, length)
    }
    

    Ref:

    1. https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#what-is-ownership

    相关文章

      网友评论

          本文标题:Rust学习笔记之Ownership

          本文链接:https://www.haomeiwen.com/subject/mjsogrtx.html