Rust基础03-所有权与函数、引用与借用

所有权与函数

在语义上,将值传递给函数和把值赋给变量是类似的:

  • 将值传递给函数将发生移动赋值
  • 函数在返回值的过程中同样也会发生所有权的转移

例:

fn main() {
    let s = String::from("Hello World");
    take_ownership(s);
    let x = 5;
    makes_copy(x);
    println!("x: {}", x);
}
fn take_ownership(some_string: String) {
    println!("{}", some_string)
}
fn makes_copy(some_number: i32) {
    println!("{}", some_number);
}

一个变量的所有权总是遵循同样的模式:

  • 把一个值赋给其它变量时就会发生移动
  • 当一个包含 heap 数据的变量离开作用域时,它的值就会被 drop 函数清理,除非数据的所有权移动到另一个变量上

例:

fn main() {
    let s1 = gives_ownership();
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);
}
fn gives_ownership() -> String{
    let some_string = String::from("hello");
    some_string
}
fn takes_and_gives_back(a_string: String) -> String {
    a_string
}

引用与借用

让函数使用某个值,但不获得其所有权

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();
    (s, length)
}

以上代码虽然做到了要求,但其过程过于繁琐,因此,实际开发中常使用以下方法

  • 引用

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

    在上述代码中,参数的类型为 &String 而不是 String

    & 符号代表引用:允许引用某些值而不取得其所有权

    引用

我们将引用作为函数参数这个行为叫做借用

  • 借用

    在程序中不可修改,和变量一样,引用默认也是不可变的

但在程序中也可存在可变引用

  • 可变引用

    在特定作用域内,对某一块数据,只能有一个可变的引用

    使得程序在编译时就可防止数据竞争

    可以通过创建新的作用域,来允许非同时的创建多个可变引用

    fn main() {
        let mut s =String::from("Hello"); {
            let s1 = &mut s;
        }
        let s2 = &mut s;
    }
    

不可同时存在一个可变引用和一个不变的引用

  • 数据竞争

    同时存在以下三种行为便会发生数据竞争:

    1. 两个或多个指针同时访问同一个数据
    2. 至少有一个指针用于写入数据
    3. 没有使用任何机制来同步对数据的访问
  • 悬空引用(Dangling References)

    悬空指针(Dangling Pointer):一个指针引用了内存中的某个地址,而这块内存可能已经释放并分配给其它人使用了

    在Rust中,编译器可保证引用永远都不是悬空引用:

    如果你引用了某些数据,编译器将保证在引用离开作用域前数据不会离开作用域

    //以下为悬空引用(此代码无法通过编译)
    fn main() {
        let r = dangle();
    }
    
    fn dangle() -> &String {
        let s = String::from("hello");
        &s
    }
    //ERROR: missing lifetime specifier
    
  • 引用的规则

    1. 一个可变的引用
    2. 任意数量不可变的引用

    在代码中,引用必须一直有效

posted on 2022-03-17 22:18  Baby091  阅读(119)  评论(0编辑  收藏  举报

导航