Rust: 引用与指针类型

指针类型

Rust中与指针相关类型有如下几种

  • Reference
    • shared reference: &T
    • immutable reference: &mut T
  • Raw Pointer
    • * const T:    对应于&T
    • * mut T:       对应于&mut T
  • Smart Pointer
    • Box<T>
    • Rc<T>
    • ...
  • Function Pointer

Reference

引用类型,primitive type 的一种,表示从某个拥有(借用到)所有权的`变量`借用它的值

//定义可变引用
    let mut x=5;
    let mut_ref=&mut x; //等价于 let ref mut mut_ref=x;
    let mut_ref2=&mut_ref;
    
//定义共享引用
    let y:i32=100;
    let shared_ref=&y;//等价于 let ref shared_ref =y;
    let shared_ref2=&shared_ref;
    
//解引用
    println!("value:y={},shared_ref={},shared_ref2={}",y,shared_ref,shared_ref2);//自动解引用
    println!("value:y={},*shared_ref={},**shared_ref2={}",y,*shared_ref,**shared_ref2);//显式解引用
    //println!("***shared_ref2={}",***shared_ref2);//错误的解引用:(type `i32` cannot be dereferenced)

//引用之间的关系
    println!("address:y={:p},shared_ref={:p},shared_ref2{:p}",&y,&shared_ref,&shared_ref2);
    println!("point to:shared_ref=>{:p},shared_ref2=>{:p}",shared_ref,shared_ref2);
    assert!(ptr::eq(&y,shared_ref));
    assert!(ptr::eq(&shared_ref,shared_ref2));

结果:

value:y=100,shared_ref=100,shared_ref2=100
value:y=100,*shared_ref=100,**shared_ref2=100
address:y=0x1c9daffa3c,shared_ref=0x1c9daffa40,shared_ref2=0x1c9daffa48
point to:shared_ref=>0x1c9daffa3c,shared_ref2=>0x1c9daffa40

Process finished with exit code 0

mut_ref2与shared_ref2说明 reference不但可以从拥有ownership的 变量 上获取 还可以从 借用到ownership的引用上获取

解引用:在The Rust Programing Languadge 中称为Implicit Deref Coercions,隐式强制解引用, 当传递一个引用作为function/method的argument又不与parameter type 不相匹配自动发生

所以无论几重引用,在关注值时不在需要添加复杂的&与*的运算,简化了代码. 同时,reference作为安全的指针,当发生了错误的解引用时会发生错误.这些相关特性都是在compile time 发生的.


&为取地址符号,即取引用,这个过程可以成为借用

*为解引用符号,当Rust的自动解引用机制使得 大多数时候省略该符号

{:p} 即实现了fmt::Pointer 的type可以通过这种方式以 指针形式 输出(变量在内存的 地址),这时不会存在自动解引用

共享引用与可变引用不能同时使用(即保证对同一value的借用时,所有共享引用的使用在可变引用之后)

Raw Pointer

即原生指针,裸指针,同c语言的指针相似.

在 The rust reference 中描述为:Raw pointers are pointers without safety or liveness guarantees.  

    let mut a=9;
    let mut b=8;
    let mut c=7;
//*mut T 的定义
    let mut_raw_p=&a  as *const i32 as *mut i32;
        /*
        //与下列方式等价
        let mut_raw_p:*mut i32=&a as *const i32 as *mut i32;
        let mut_raw_p=&mut a as *mut i32;
        let mut_raw_p:*mut i32=&mut a;
         */
//*const T 的定义
    let const_raw_p=&a as *const i32;
    let const_raw_p2:*const i32=&a;

//raw pointer的使用
    unsafe {
        //raw pointer 的解引用操作和相关函数都时unsafe的
        let pb=&b as *const i32;
        println!("&a={:p},&b={:p},&c={:p}",&a,&b,&c);

        //offset(),add()等函数
        println!("address:a={:p},b={:p},c={:p},",pb.offset(-1),pb.offset(0),pb.add(1));

        //raw pointer 不具有自动解引用作用
        println!("value:a={},b={},c={},",*pb.offset(-1),*pb.offset(0),*pb.add(1));

        // 指针越界
        println!("value:p1={},p2={},p3={},",*pb.offset(-10),*pb.offset(10),*pb.add(100));
    }

结果:

&a=0x8ed6ff514,&b=0x8ed6ff518,&c=0x8ed6ff51c
address:a=0x8ed6ff514,b=0x8ed6ff518,c=0x8ed6ff51c,
value:a=9,b=8,c=7,
value:p1=184832304,p2=-311429808,p3=-311429864,

原生指针类似C/C++的指针,不能自动解引用,也没有安全检查,需要unsafe 包围

使用相关函数add(),offset()等实现加减,而非直接使用+ ,-(error[E0369]: cannot add `*const i32` to `*const i32`)

Smart Pointer

即智能指针,在The Rust Programming Language 中描述为:

Smart pointers , are data structures that not only act
like a pointer but also have additional metadata and capabilities .
表现为指针,但不是指针,而是数据结构,并且拥有比指针更多的数据与能力
  • smart pointers implement the Deref and Drop traits

    • Deref trait 使得 该数据结构(struct) 可以像 引用一样使用,即自定义实现解引用操作,(Rust substitutes the * operator with a call to the deref method )
    • Drop trait 允许自定义 该数据结构(struct) 实例 out of scope时的行为,通过这种方式,编译器自动添加代码达到释放内存回收资源的目的
  • references  only borrow data; in contrast, in many cases, smart pointers own the data they point to.

Box<T>

Boxes allow you to store data on the heap rather than the stack.

What remains on the stack is the pointer to the heap data

使用场景:

  • 编译时不确定大小的 动态数据结构(如递归实现的Recursive Typestack上留下确定大小的pointer,heap上运行时分配内存)
  • 大量数据或大型数据结构,(stack的容量有限且珍贵),保证在ownership的转移时不作额外的复制操作
​//Box<T>的定义
    let stack_begin:usize=1;
    let x=Box::new(1);
    let y=Box::new([99;1024]);
    let z=Box::new(-1);
    let a :[usize;4]=[1,2,3,4];
    let stack_end:usize=2;

//act like a reference:自动解引用,显式解引用
    assert_eq!(*y,*(y.deref()));// Rust解引用的实质就是调用 deref()方法
    println!("value:x={},y={},*x={},*y={}",x,y[3],*x,(*(y.deref()))[3]);

//在heap中存储大量数据
    println!("address:stack_begin={:p},x={:p},y={:p},z={:p},a={:p},stack_end={:p}",&stack_begin,&x,&y,&z,&a,&stack_end);

//在heap中存储未知大小的数据:参考https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes

结果:

value:x=1,y=99,*x=1,*y=99
address:stack_begin=0x8d7b10e7b8,x=0x8d7b10e7c0,y=0x8d7b10e7c8,z=0x8d7b10f7d0,a=0x8d7b10f7d8,stack_end=0x8d7b10f7f8

用Box::new() 包裹let 语句发等号右边的表达式,即可实现内存分配在heap上

从打印出的地址关系可以看出,Box中的数据,无论其数据结构 在stack中只占用了一个指针大小即8Byte,64bit的内存空间,即使数据大小远超这个值

Box可以作为一种indirection,解决在compile time无法确定动态数据结构大小的问题;事实上所有动态数据结构都使用这一原理(如 String)

  • 匹配 实现某种trairt 的type 而非一个具体的type :? TODO

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值