前言:
此刻小伙伴们对“c语言中引用传递”可能比较注意,朋友们都想要学习一些“c语言中引用传递”的相关文章。那么小编同时在网上搜集了一些有关“c语言中引用传递””的相关资讯,希望大家能喜欢,看官们快快来了解一下吧!前面在介绍所有权的时候,我们有提到:
将变量A赋值给变量B之后,所有权就已经发生改变,A将不再有效。将变量A传递给方法,变量A对数据的所有权也发生了改变,变量A不再有效;
那么有没有一个方式可以让A继续有效,但是其他变量或方法又能访问到变量A所指向的数据呢?
这就是我们这篇文章需要学习的引用与借用。
引用与借用
整体来说就是A拥有一个玩具的所有权,但是它的小伙伴B想借着玩一下(所有权还是A的),那怎么办呢?
A就将自己的玩具借给B,这个行为就是借用?
怎么借给B呢?
从某种意义上来说就是将A的指针值复制了一份给B,B使用完成之后,就销毁掉了。对A没有任何影响。这个就是引用。B引用了A的值。
在变量名称前面加上 & 符号就完成了引用。如下所示 &s1 是将s1 的引用传入到函数中。
fn main() { let s1 = String::from("hello"); // 引用s1, 也就是将s1 指向 堆中的hello的指针给了方法参数 let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len);}// 需要注意的是参数类型 也变成了 &String 而不是 Stringfn calculate_length(s: &String) -> usize { s.len()}// s作用域完成,销毁的只是s本身,对s1没有任何影响小结引用的重要特点是,它们只是对值的借用,不会拥有所有权。这意味着,当你创建一个引用时,原始变量的所有权仍然保持不变。引用存放的是指向被引用值的内存地址,但不能认为它就是存放的指针,你可以认为他是特殊的数据类型,有别于指针的数据类型,因为它还携带了其他业务逻辑。我们将创建一个引用的行为称为 借用(borrowing)可变引用
引用分为两种:
可变引用:申明方式:&mut x,内容可以被修改不可变引用:申明方式:&x,内容不可被修改
fn main() { let mut s = String::from("hello"); // 可变引用 change(&mut s);}// 可变引用值可以被修改,当然要s变量也必须能够修改fn change(some_string: &mut String) { some_string.push_str(", world");}
可变引用有一个很大的限制:如果你有一个对该变量的可变引用,你就不能再创建对该变量的引用(目的是避免数据竞争写)。
fn main() { let mut s = String::from("hello"); let r1 = &mut s; // s已经有一个r1可变引用,不能有第2个,这里会编译失败 let r2 = &mut s; println!("{}, {}", r1, r2);}
同时使用可变与不可变引用时也采用的类似的规则:
fn main() { let mut s = String::from("hello"); let r1 = &s; // 没问题 let r2 = &s; // 没问题 let r3 = &mut s; // 大问题 println!("{}, {}, and {}", r1, r2, r3);}
fn main() { let mut s = String::from("hello"); let r1 = &s; // 没问题 let r2 = &s; // 没问题 println!("{} and {}", r1, r2); // 此位置之后 r1 和 r2 不再使用 let r3 = &mut s; // 没问题 println!("{}", r3);}悬垂引用
也就是我们引用了一个变量,但是被引用变量内存被回收了。这个引用就变成了悬垂引用。
fn main() { let reference_to_nothing = dangle();}fn dangle() -> &String { // dangle 返回一个字符串的引用 let s = String::from("hello"); // s 是一个新字符串 &s // 返回字符串 s 的引用} // 这里 s 离开作用域并被丢弃。其内存被释放。返回的引用就成了悬垂引用