Rust语言学习

Rust 引用与借用

2020-03-20  本文已影响0人  kaiv2

引用与借用

fn main() {
  let s1 = String::from("abc");
  let l = f1(&s1);
  println!("s1 = {}, len = {}", s1, l);
}

fn f1(s: &String) -> usize {
  s.len()
}

这里将s1传给了 f1函数,使用的是&s1,f1定义的形参类型是&String。这些&符号就是引用,它们允许你使用值但不获取所有权。

&s语法 让我们创建了一个指向s1的引用,但是不拥有它。因为不拥有这个值,在离开作用域时也不需要drop特殊操作。

我们将获取引用作为函数参数称为借用。正如变量默认是不可边的,应用也是一样。

fn f1(s: &String) -> usize {
  s.push_str("hello"); // 这里将发生错误,尝试修改不可变的借用的值
  s.len();
}

与运算符 & 引用相反的操作是*解引用

可变引用

fn main() {
  let mut s = String:from("hello");
  change(&mut s);
}

fn change(s: &mut String) {
  s.push_str(", world");
}

首选将s改为 mut的,然后必须创建一个可变引用&mut s和接受一个可变引用s: &mut String

不过可边引用有很大的限制,在特定作用域的特定数据有且只有一个可变引用

let mut s1 = String::from("hello");
let s2 = &mut s1;
let s3 = &mut s1;
println!("{}, {}", s2, s3);

这里将报错,这个限制的好处是Rust在编译时就避免数据竞争数据竞争类似于竞态条件。它由这三个条件造成:

数据竞争会导致未定义行为,难以在运行时追踪,且难以诊断和恢复。Rust避免了这种情况发生,因为它甚至不会编译存在数据竞争的代码。

let mut s = String::from("hello");
{
  let r1 = &mut s;
} // r1 离开了作用域,可以创建一个新的引用
let r2 = &mut s;

类似的规则也存在于可变引用和不可变引用中。

let mut s = String::from("hello");

let r1 = &s; // 可以
let r2 = &s; // 可以
let r3 = &mut s; // 不行

Rust不允许不可变引用和可变引用同时指向一个值,不可变引用不希望再读取值时被修改。多个不可变引用是可以的。

悬垂引用

在具有指针的语言中,很容易变量指向一个已释放的内存,而错误的产生一个 悬垂指针。尝试创建一个悬垂指针:

fn main() {
  let s  = f1();
}

fn f1() -> &String {
  let s = String::from("hello"); // 创建字符串,分配内存
  &s // 返回字符串的引用
} // s 离开作用域,释放内存

s离开作用域时,s将被释放。尝试返回s的引用,Rust不允许这么做,这里将发生错误。

引用的规则

总结:

上一篇下一篇

猜你喜欢

热点阅读