zoukankan      html  css  js  c++  java
  • Rust“所有权”思想

    fn main() {
                    let s1 = String::from("hello"); 
                    let s2 = s1; 
                     println!("s1 : {}", s1);
                    let s3 = s2.clone();
                     println!("s2 : {}", s2);
                     println!("s3 : {}", s3);
    
    }
    does not implement the `Copy` trait
    cargo build
       Compiling own v0.1.0 (/data2/rust/clone4)
    error[E0382]: borrow of moved value: `s1`
     --> src/main.rs:4:24
      |
    2 |         let s1 = String::from("hello"); 
      |             -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
    3 |         let s2 = s1; 
      |                  -- value moved here
    4 |          println!("s1 : {}", s1);
      |                              ^^ value borrowed here after move
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0382`.
    error: could not compile `own`.
    
    To learn more, run the command again with --verbose.
    fn main() {
                    let s1 = String::from("hello"); 
                    let s2 = s1; 
                     //println!("s1 : {}", s1);
                    let s3 = s2.clone();
                     println!("s2 : {}", s2);
                     println!("s3 : {}", s3);
    
    }
    cargo build
       Compiling own v0.1.0 (/data2/rust/clone4)
        Finished dev [unoptimized + debuginfo] target(s) in 0.50s
    [root@bogon clone4]# cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/own`
    s2 : hello
    s3 : hello

    1、Rust使用所有权系统(ownership)管理内存,不同于Ruby的GC和C语言的亲自分配和释放。原理是编译器编译时根据一系列规则检查,从而保证运行时的安全和效率。(我理解为对代码的预处理,检查栈和堆使用的合理性)

    2、栈(Stack)和堆(Heap)是代码在运行时可供使用的内存。使用栈内存大小固定且效率高。反之,堆内存大小动态且效率相对较低。因为堆内存是动态所以需要指针访问,从而保证动态分配内存,而Rust的所有权就是管理堆数据。

    3、Rust中任一变量在任一时刻有且只有一个所有者(owner)。当所有者离开作用域(表现在代码中的“”后会自动执行 drop 释放当前作用域内存),这个值将被丢弃。例如:

    {
                         // s 无效
        let s = "hello"; // s 进入作用域,有效。此时hello字符串是硬编码进程序的,不可改变。
    }                    // s 离开作用域,无效。此时自动调用 drop 函数 (源于 C++ 的 RAII)
    

    4、动态长度的字符串String数据分配在堆上。例如:

    let mut s = String::from("hello");
    s.push_str(" world");
    println!("{}", s);

    5、堆上的数据占用内存大,所以有 移交 和 克隆 的区别。例如:

    let s1 = String::from("hello"); // 此时在堆上初始化hello字符串,所有者是s1
    let s2 = s1;                    // 此时堆上的hello字符串,所有者从s1移交给了s2
                                    // 根据“任一时刻有且只有一个所有者”,s1不存在了
    let s3 = s2.clone();            // 此时在堆上初始化第二个hello字符串,所有者是s3
    

    6、栈上的数据占用内存小,所以都是 克隆。例如:

    let x = 5;
    let y = x;                      // 此时栈上有两个5,所有者分别是 x和 y
    

    7、将值传递给函数,等价于将值所有者移交给函数参数变量的所有者,函数结束将释放。例如:

    fn main() {
        let s1 = gives_ownership();
        let s2 = String::from("hello");
        let s3 = takes_and_gives_back(s2);
    } 
      // 此时执行drop释放堆中两个 hello 字符串,所有者是:s1 和 s3
      // hello -> s1
      // hello -> s2 -> a_string -> s3
    fn gives_ownership() {
        let some_string = String::from("hello");
        some_string
    }
    fn take_and_gives_back(a_string: String) -> String {
        a_string
    }

     cat src/main.rs 
    fn main() {
        let s1 = gives_ownership();
            println!("s1 : {}", s1);
        //let s2 = String::from("hello");
        //let s3 = takes_and_gives_back(s2);
    } 
      // 此时执行drop释放堆中两个 hello 字符串,所有者是:s1 和 s3
      // hello -> s1
      // hello -> s2 -> a_string -> s3
    fn gives_ownership() {
        let some_string = String::from("hello");
        some_string
    }
    fn take_and_gives_back(a_string: String) -> String {
        a_string
    }
    cargo build
       Compiling own v0.1.0 (/data2/rust/ownship)
    error[E0277]: `()` doesn't implement `std::fmt::Display`
     --> src/main.rs:3:22
      |
    3 |     println!("s1 : {}", s1);
      |                         ^^ `()` cannot be formatted with the default formatter
      |
      = help: the trait `std::fmt::Display` is not implemented for `()`
      = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
      = note: required by `std::fmt::Display::fmt`
      = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
    
    error[E0308]: mismatched types
      --> src/main.rs:12:5
       |
    10 | fn gives_ownership() {
       |                      - help: try adding a return type: `-> std::string::String`
    11 |     let some_string = String::from("hello");
    12 |     some_string
       |     ^^^^^^^^^^^ expected `()`, found struct `std::string::String`
    
    error: aborting due to 2 previous errors
    
    Some errors have detailed explanations: E0277, E0308.
    For more information about an error, try `rustc --explain E0277`.
     

    8、由上可见,函数使用完一个变量后,值就被回收清理了。如果函数后继续使用,就需要传进去再反回来。例如:

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

    cat src/main.rs 
    fn main() {
        //let s1 = gives_ownership();
            //println!("s1 : {}", s1);
        let s2 = String::from("hello");
        let s3 = take_and_gives_back(s2);
            println!("s3 : {}", s3);
    } 
      // 此时执行drop释放堆中两个 hello 字符串,所有者是:s1 和 s3
      // hello -> s1
      // hello -> s2 -> a_string -> s3
    //fn gives_ownership() {
    //    let some_string = String::from("hello");
    //    some_string
    //}
    fn take_and_gives_back(a_string: String) -> String {
        a_string
    }
    [root@bogon ownship]# cargo build
       Compiling own v0.1.0 (/data2/rust/ownship)
        Finished dev [unoptimized + debuginfo] target(s) in 0.41s
    [root@bogon ownship]# cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/own`
    s3 : hello
     
  • 相关阅读:
    如果你正在找工作,也许这七个方法会帮到你
    WebSocket 浅析
    关系数据库涉及中的范式与反范式
    MySQL字段类型与合理的选择字段类型
    ER图,数据建模与数据字典
    详解慢查询
    MySQL的最佳索引攻略
    后端技术演进
    MySQL主从复制(BinaryLog)
    MySQL读写分离
  • 原文地址:https://www.cnblogs.com/dream397/p/14200767.html
Copyright © 2011-2022 走看看