Skip to content

Latest commit

 

History

History
233 lines (197 loc) · 5.14 KB

L06-pointer-types.org

File metadata and controls

233 lines (197 loc) · 5.14 KB

CIS198 Lecture 6: 指针类型

指针:reference & deference

  1. 引用 & reference
  2. 解引用 * dereference
int val = 1234;
int *p = &val;
printf("p  = %p\n", p);
printf("*p = %d\n", *p);
// val = 666;
*p = 888; // 可变性
printf("*p = %d\n", *p);
p  = 0x7ff7ba3052c4
*p = 1234
*p = 888
  1. &T 引用
  2. &mut T 可变引用
let mut val = 123;
{
    let mut p = &mut val;
    println!("{:p}", p);
    println!("{}", p);
    println!("{}", *p);
    *p = 222;
}
val = 444;
println!("{}", val);
0x7ff7b778abd4
123
123
444

Box<T>

  1. 智能指针 smart pointer
  2. 在堆上分配内存 | link
    • malloc(...)
  3. Box<T> 是 Rust 中最常见的智能指针
    • &v
    • *v
  4. 它是简单的封装,除了将值存储在堆上外,并没有其它性能上的损耗
  5. 使用场景:
    • 特意的将数据分配在堆上
    • 数据较大时,又不想在转移所有权时进行数据拷贝
    • 类型的大小在编译期无法确定,但是我们又需要固定大小的类型时
      enum List {
          Nil,
          Cons(i32, Box<List>),
      }
              
    • Trait Object,用于说明对象实现了一个特征,而不是某个特定的类型
      fn make_clousre() -> Box<dyn Fn(i32) -> i32> {
      
      }
              

    简单实现 MyBox

    use std::ops::Deref;
    
    #[allow(unused_variables)]
    #[allow(dead_code)]
    
    struct MyBox(i32);
    
    impl Deref for MyBox {
        type Target = i32;
    
        fn deref(&self) -> &i32 {
            println!("deref in MyBox");
            &self.0
        }
    }
    
    impl Drop for MyBox {
        fn drop(&mut self) {
            println!("drop in MyBox");
        }
    }
        

Rc<T>

  1. 引用计数 | link
  2. 使用 .clone() 获取只读引用
    use std::rc::Rc;
    
    let v1 = Box::new(123);
    println!("Box v1 = {:p}", v1);
    println!("Box v1.clone = {:p}", v1.clone());
    println!("Box v1.clone = {:p}", v1.clone());
    
    let v2 = Rc::new(123);
    println!("Rc  v2 = {:p}", v2);
    println!("Rc  v2.clone = {:p}", v2.clone());
    println!("Rc  v2.clone = {:p}", v2.clone());
        
    Box v1 = 0x600002f20000
    Box v1.clone = 0x600002f2c050
    Box v1.clone = 0x600002f2c050
    Rc  v2 = 0x600002d28bb0
    Rc  v2.clone = 0x600002d28bb0
    Rc  v2.clone = 0x600002d28bb0
        
  3. 优点是可以放到多处,可以共享所有权
    use std::rc::Rc;
    
    #[derive(Debug)]
    struct Foo {
        v: Box<i32>,
    }
    
    #[derive(Debug)]
    struct Bar {
        v: Rc<i32>,
    }
    
    let v1 = Box::new(123);
    let f1 = Foo { v: v1};
    // 没有所有权,会报错
    // let f2 = Foo { v: v1 };
    
    let v2 = Rc::new(222);
    let b1 = Bar { v: v2.clone() };
    let b2 = Bar { v: v2 };
        
    error: Could not compile `cargoXIpimx`.
        
  4. 当 referenced count == 1 时可以修改
    let mut v2 =  Rc::new(123);
    let r1 = Rc::get_mut(&mut v2);
    println!("r1 = {:?}", r1);
        

循环引用 => Weak<T>

  1. 弱引用 Weak
  2. referenced counter
    • strong referenced counter
    • weak referenced counter

内部可变性

介绍

use std::cell::{Cell, RefCell};

#[allow(unused_variables)]
#[allow(dead_code)]
#[derive(Debug)]
struct Foo {
    x: Cell<i32>,
    y: RefCell<u32>,
}

fn main() {
    let foo1 = Foo {
        x: Cell::new(123),
        y: RefCell::new(345),
    };
    println!("foo1 = {:#?}", foo1);

    foo1.x.set(666);
    println!("foo1 = {:#?}", foo1);

    println!("foo1.x = {:#?}", foo1.x.get());
}

Cell<T>

  1. 内部可变性
  2. get() 获取值
  3. set() 设置值
  4. T 只能设置 Copy 类型

RefCell<T>

  1. 运行时动态检测,可能会造成 panic
  2. T 可以是任何类型
  3. 通过 borrow() / borrow_new() 进行操作
let v1 = RefCell::new(vec![1]);

{
    let mut inner = v1.borrow_mut();
    inner.push(2);
}
println!("v1 = {:?}", v1.borrow());
let v1 = RefCell::new(vec![1]);

let mut inner = v1.borrow_mut();
inner.push(2);

println!("v1 = {:?}", v1.borrow());

let mut inner2 = v1.borrow();

上述代码会 panic

thread 'main' panicked at src/main.rs:17:30:
already mutably borrowed: BorrowError
struct Foo {
    v: Rc<RefCell<Vec<i32>>>,
    u: Rc<Vec<i32>>,
}

* const T*mut T

  1. 和 c 语言类似的裸指针
  2. 很少使用,基本上出现场景就是标准库
  3. unsafe