指针

指针是个通用概念,它表示内存地址这种类型,其引用或“指向”其他数据。Rust中的指针是“第一类公民”(first-class values),可以将它们移动或复制,存储到数据结构中并从函数中返回。Rust提供了多种类型的指针:

  • 引用(Reference),共享引用&,可变引用&mut
  • 原生指针,又叫裸指针(Raw Pointer),*const*mut
  • 智能指针(Smart Pointer),Box,Rc等

引用

Rust中使用&符号表示引用,也叫引用操作符。其使用场景是只使用类型的值但不获取其所有权,同时Rust的引用规则为:

  • 在作用域中的数据有且只能有一个可变引用;
fn main(){
    let mut s  = String::from("hello");
    let r1 = &mut s;
    let r2 = &mut s;    //error
    
    println!("{} " ,   r1)
}

编译错误如下:

6 |     let r1 = &mut s;
  |              ------ first mutable borrow occurs here
7 |     let r2 = &mut s;    //error
  |              ^^^^^^ second mutable borrow occurs here
  • 可以有多个不可变引用;
  • 不能同时拥有不可变引用和可变引用。
let mut s = String::from("hello");

let r1 = &s; // no problem
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);

编译错误如下:

8  | let r3 = &mut s; // BIG PROBLEM
   |          ^^^^^^ mutable borrow occurs here
  • 引用必须总是有效的

悬垂引用

在存在指针的语言中,容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者或者已经释放。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当我们拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &'static String {
    let s = String::from("hello");
    &s
}

编译错误如下:

error[E0515]: cannot return reference to local variable `s`
 --> src/main.rs:8:5
  |
8 |     &s
  |     ^^ returns a reference to data owned by the current function

引用&借用

非要给区分ref和&到底哪个是引用,哪个是借用。我们可以先从词性划分,引用我归类为名词,而借用归类为动词。&A在表达式上 表示借用A,这是一个动作,那结果就是产出一个引用类型。所以let ref B表示声明了一个引用类型,它只能绑定到某次借用动作上

作者:kayryu 链接:https://www.jianshu.com/p/ac519d8c5ec9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解引用

与引用相反的操作被称为解引用(dereferencing)

& 和 ref

ref在等于号左边等价于&符号在等号右边

let ref x = 1;
let x = &1;

&在等于号左边等价于*号在等于号右边

let &y = x;
let y = *x;

智能指针

智能指针的概念起源于C++,智能指针是一类数据结构,他们的表现类似指针,但是拥有额外的元数据和功能。

在Rust中,引用和智能指针的一个的区别是引用是一类只借用数据的指针;相反,在大部分情况下,智能指针拥有他们指向的数据。Rust标准库中不同的智能指针提供了比引用更丰富的功能:

  • Box,用于在堆上分配数据。
  • Rc,一个引用计数类型,其数据可以有多个所有者。
  • Ref 和 RefMut,通过RefCell访问,一个在运行时而不是在编译时执行借用规则的类型。