25.智能指针.rs
生活随笔
收集整理的這篇文章主要介紹了
25.智能指针.rs
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
/*
參考文章:
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();
}
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的25.智能指针.rs的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 24.内存操作Copy-Move-Clo
- 下一篇: 26.PhantomData幽灵数据.r