/*
参考文章:
https://zhuanlan.zhihu.com/p/112307245
https://rustcc.cn/article?id=76e5f3fb-20b9-48c9-8fc6-a0aad40ced8c
https://www.codercto.com/a/27950.html
https://www.twle.cn/c/yufei/rust/rust-basic-smart-pointers.html
https://www.cnblogs.com/dream397/p/14185003.html1.引用和智能指针的一个的区别是引用是一类只借用数据的指针;相反,在大部分情况下,智能指针拥有他们指向的数据
2.它与普通数据结构的区别在于智能指针实现了Deref和Drop这两个traits。实现Deref可以使智能指针能够解引用,而实现Drop则使智能指针具有自动析构的能力。Box<T>:用来在堆内存中保存数据使用的
Rc<T>:一个引用计数类型,其数据可以有多个所有者。
Ref<T> 和 RefMut<T>,通过RefCell<T>访问,一个在运行时而不是在编译时执行借用规则的类型。*///测试栈区大小,经过测试大于1兆小于2兆,当栈申请大于2兆的时候编译没有问题,运行会出现fatal runtime erro:stack overflow
fn test_1() {let c: [i32; 1 * 1024 * 1024];
}//复习一下引用
//Rust中使用&符号表示引用,也叫引用操作符。其使用场景是只使用类型的值但不获取其所有权。同时Rust的引用规则为:
// 在作用域中的数据有且只能有一个可变引用;
// 可以有多个不可变引用;
// 不能同时拥有不可变引用和可变引用。
fn test_2() {println!("----------------------test_2-----------------");let adrr = 123;let addr1 = &adrr; // 通过 & 得到引用,默认是不可变的let addr2 = &adrr; // 通过 & 得到引用,默认是不可变的println!("{}-{}", *addr1, *addr2); // 输出里面的值println!("{}-{}", addr1, addr2); // 不带*号也可以的,这是因为编译器识别了这个类型,取出来了里面的值println!("{:p}-{:p}", addr1, addr2); // 其实这个两个都是地址//println!("{:p}", adrr); // 这样就不行let mut vec = vec![1, 2, 3]; // 要获取可变引用,必须先声明可变绑定let new_vec = &mut vec; // 通过 &mut 得到可变引用//let new_vec2 = &mut vec; // 通过 &mut 得到可变引用new_vec.push(40);println!("{:?}", vec);let new_vec2 = &mut vec; //不知道为什么在这里又可以再次引用了???let mut str2 = String::from("world");let r1 = &str2;let r2 = &mut str2; //只声明没有问题,一旦有使用者就会编译报错// println!("{}, {}, and", r1, r2); // ERROR:不能同时拥有不可变引用和可变引用
}//研究特性Deref
//Deref就是用*取值的操作
fn test_3() {println!("----------------------test_3-----------------");let x = 5; // 值类型数据let y = Box::new(x); // y 是一个智能指针,指向堆上存储的数据 5println!("{}", 5 == x);println!("{}", 5 == *y); // 为了访问 y 存储的具体数据,需要解引用use std::ops::Deref;struct MyBox<T>(T);impl<T> MyBox<T> {// 范型方法fn new(x: T) -> MyBox<T> {MyBox(x)}}impl<T> Deref for MyBox<T> {type Target = T;fn deref(&self) -> &T {&self.0 // 返回数据}}let x = 5;let y = MyBox::new(x); // 调用静态方法 new() 返回创建一个结构体实例println!("5==x is {}", 5 == x);println!("5==*y is {}", 5 == *y); // 解引用 yprintln!("x==*y is {}", x == *y); // 解引用 y
}//研究特性Drop
//Drop对于智能指针非常重要,它是在智能指针被丢弃时自动执行一些清理工作,这里所说的清理工作并不仅限于释放堆内存,还包括一些释放文件和网络连接等工作
fn test_4() {println!("----------------------test_4-----------------");use std::ops::Drop;#[derive(Debug)]struct S(i32);impl Drop for S {fn drop(&mut self) {println!("drop {}", self.0);}}let x = S(1);println!("create x: {:?}", x);{let y = S(2);println!("create y: {:?}", y);}//-------------------------use std::ops::Deref;struct MyBox<T>(T);impl<T> MyBox<T> {fn new(x: T) -> MyBox<T> {MyBox(x)}}impl<T> Deref for MyBox<T> {type Target = T;fn deref(&self) -> &T {&self.0}}impl<T> Drop for MyBox<T> {fn drop(&mut self) {println!("dropping MyBox object from memory ");}}let x = 50;MyBox::new(x);MyBox::new("Hello");
}//Box
//Box<T>是堆上分配的指针类型,称为“装箱”(boxed),其指针本身在栈,指向的数据在堆
//box关键字会调用Rust内部的exchange_malloc和box_free方法来管理内存
//Box使用场景:
//1.递归类型和trait对象。Rust需要在编译时知道一个类型占用多少空间,Box<T>的大小是已知的。
//2.“大”的数据转移所有权。用Box<T>只需拷贝指针。
//       a.当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候;
//       b.当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候;
//       c.当希望拥有一个值并只关心它的类型是否实现了特定trait而不是具体类型的时候;
fn test_5() {println!("----------------------test_5-----------------");let x = Box::new("hello");println!("{:?}", x.chars());//递归类型的经典示例:use List::{Cons, Nil};/*//无法编译通过的例子,原因时编译器无法算出他所需的大小enum List{Con(i32,List),Nil}fn main(){let list = Con(1,Con(2,Con(3,Nil)));}//改进enum LIst{Con(i32,Box<List>),Nil}fn main(){let list = Con(1,Box::new(Con(2,Box::new(3,Nil))));}*/#[derive(Debug)]enum List<T> {Cons(T, Box<List<T>>),Nil,}let recursive_list: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Nil))));println!("{:?}", recursive_list); // 打印出:Cons(1, Cons(2, Nil))//trait对象的示例:trait T {fn m(&self) -> u64;}struct S {i: u64,}impl T for S {fn m(&self) -> u64 {self.i}}fn f(x: Box<dyn T>) {println!("{}", x.m())}let s = S { i: 100 };println!("{}", s.m());let b: Box<S> = Box::new(S { i: 100 });f(b);
}//Rc <T>引用计数智能指针  reference counting
//使用场景:当我们希望在堆上分配一些内存供程序的多个部分去读取,而且无法在编译时确定程序的哪一部分会最后结束使用它的时候。
//Rc<T>只能用于单线程场景。(多线程使用arc)
//特征:允许相同数据有多个所有者,在编译时执行不可变借用检查。
fn test_6(){println!("----------------------test_6-----------------");use std::rc::Rc;enum List{Con(i32,Rc<List>),Nil}let a = Rc::new(List::Con(5,Rc::new(List::Con(10,Rc::new(List::Nil)))));let b = List::Con(3,Rc::clone(&a));let c = List::Con(4,Rc::clone(&a));//打印引用计数,结果应该是3println!("the Rc count is {}",Rc::strong_count(&a));//--------------------------------------------------------struct Owner {name: String,// ...other fields}struct Gadget {id: i32,owner: Rc<Owner>,// ...other fields}let gadget_owner: Rc<Owner> = Rc::new(  //堆分配Owner, 产生一个Rc<Owner>计数Owner {name: "Gadget Man".to_string(),});  //现在有一个Owner,在堆中,一个Rc<Owner>, 指针let gadget1 = Gadget {id: 1,owner: Rc::clone(&gadget_owner),  //获得一个指向堆中Owner的Rc<Owner>,计数加一};let gadget2 = Gadget {id: 2,owner: Rc::clone(&gadget_owner), //获得指针,计数加一};  //现在有一个Owner, 三个Rc<Owner>drop(gadget_owner);  //std::mem::drop,销毁一个Rc<Owner>,内存Owner还在//剩余两个Rc<Owner>仍然指向Ownerprintln!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name)
}//RefCell <T>
//作用:RefCell<T>用于当你确信代码遵守借用规则,而编译器不能理解和确定的时候。
//特征:单一所有者,在运行时执行不可变或可变借用检查。
fn test_7(){}fn main() {test_1();test_2();test_3();test_4();test_5();test_6();test_7();
}

25.智能指针.rs相关推荐

  1. 【转】C++面试题(四)——智能指针的原理和实现

    C++面试题(四)--智能指针的原理和实现 tanglu2004 http://blog.csdn.net/worldwindjp/   C++面试题(一).(二)和(三)都搞定的话,恭喜你来到这里, ...

  2. Linux 内核里的“智能指针”【转】

    转自:http://blog.jobbole.com/88279/ 众所周知,C/C++语言本身并不支持垃圾回收机制,虽然语言本身具有极高的灵活性,但是当遇到大型的项目时,繁琐的内存管理往往让人痛苦异 ...

  3. C++智能指针及其简单实现

    原文:http://www.cnblogs.com/xiehongfeng100/p/4645555.html C++智能指针及其简单实现 本文将简要介绍智能指针shared_ptr和unique_p ...

  4. 有关智能指针(shared_ptr)的讨论

    1. boost::shared_ptr的用法2. boost::shared_ptr的实现机制3. 使用boost::shared_ptr的注意事项4. std::tr1::shared_ptr和b ...

  5. 智能指针auto_ptr介绍

    我们大家都知道,new一定要和delete配合使用,但是有一种情况可能会使这种配对失效,如下程序: #include <iostream> using namespace std; cla ...

  6. C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr

    1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...

  7. c++ 智能指针_详解 C++ 11 中的智能指针

    C/C++ 语言最为人所诟病的特性之一就是存在内存泄露问题,因此后来的大多数语言都提供了内置内存分配与释放功能,有的甚至干脆对语言的使用者屏蔽了内存指针这一概念.这里不置贬褒,手动分配内存与手动释放内 ...

  8. C++智能指针(三)总结

    https://blog.csdn.net/nou_camp/article/details/70195795 在上一篇博客中(C++智能指针(二))模拟实现了三种智能指针. 其中最好的就是share ...

  9. C++智能指针(二)模拟实现三种智能指针

    https://blog.csdn.net/nou_camp/article/details/70186721 在上一篇博客中提到了Auto_ptr(C++智能指针(一)),下面进行模拟实现Auto_ ...

最新文章

  1. svm理论与实验之11:svm开发工具包LibSVM
  2. 离散数学及其应用第6版中文版勘误
  3. 整理了一下目前的专栏文章,基本可以完整解决普通问题了 - 知乎专栏
  4. @NotNull 、@NotBlank、@NotEmpty区别
  5. Android 高仿微信6.0主界面 带你玩转切换图标变色
  6. svn+post-commit实现自动部署(转)
  7. Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)...
  8. Android---什么是3G
  9. C# 中用stopwatch测试代码运行时间
  10. phantom物料 issue
  11. append 注意事项
  12. python-图像金字塔
  13. 服务监管框架下的 IT 运维服务与绩效管理体系建设
  14. Java调用dll文件
  15. 用计算机写作文主题,《用计算机写作文》教学设计(周未定)
  16. 微软:人工智能迅速崛起,面临着严重的技术短缺
  17. 拒酒词,社交必备!!!
  18. 华为新版Datacom认证介绍
  19. 使用微搭搭建天气预报小程序
  20. c#用串口传输二进制文件 xmodem协议

热门文章

  1. 多租户数据库设计方法:共享数据库表
  2. Servlet_概述
  3. 递归-递归实现数字累加
  4. Spring Cloud Stream的使用(上)
  5. 二叉树的遍历算法(三级)
  6. 使用Github(目的、基本你概念、注册账号)
  7. ElasticSearch(二)索引管理
  8. 结合webpack配置_前端 Webpack 工程化的最佳实践
  9. PyTorch深度学习实践07
  10. C#窗体内控件大小随窗体等比例变化