Rust のメモリーコンテナー的な何かをわかりやすく整理したチートシートのメモ; T, Cell, RefCell, AtomicT, Mutex, RwLock, Rc, Arc
作ったので GitHub ↑ しつつ、なんとなくすごい久しぶりに Qiita に初心者さんに優しそうな雰囲気を装った解説↓
も書いてみました。ちなみに reddit ↓
にもポストしてみました。 reddit はとても参考になる議論がおおむね建設的にものすごい勢いで発生してくれるので嬉しいです。チートシートとしての意図と図面の都合による nitpick たちは README に注釈を付けるといいかなと思います。Allocationからの線の見直しなど a better なシートの提案はうまく取り込んで、できるだけウソの無い、でもチートシートの意図としてはわかりやすさを維持した調整をしたいと思います。
と、それだけ書いたのではわざわざブログにメモを残す理由が薄いので、ここには C++ と Rust でチートシートに掲載したメモリーコンテナー的なそれの大雑把なコードを、翻訳が通るソースとして書き残してみます。
おまけ: C++ の &≈ptr と (mutable)/const 系、Rust の &≈ptr と mut/const 系
// C++ #include <memory> #include <shared_mutex> #include <vector> #include <iostream> int main() { using T = int; using V = std::vector<T>; // mutable value T valm = 1; // const ref -> mutable value T& refc_valm = valm; refc_valm = 10; // const ref -> const value T const& refc_valc = valm; std::clog << refc_valc << " <- It's read only.\n"; // mutable ptr -> mutable value T* ptrm_valm = &valm; *ptrm_valm = 11; // const ptr -> mutable value T* const ptrc_valm = &valm; *ptrc_valm = 21; // const ptr -> const value const T* const ptrc_valc = &valm; std::clog << *ptrc_valc << " <- It's read only.\n"; // heap, ≈ 'static lifetime of Rust T* ptrm_heap_static_lifetime = new int(-1); // heap, ≈ mut Box<T> of Rust std::unique_ptr<T> ptrm_heap_single_owner_valm = std::make_unique<T>(-1); *ptrm_heap_single_owner_valm = -100; // heap, ≈ Box<T> of Rust std::unique_ptr<const T> ptrm_heap_single_owner_valc = std::make_unique<T>(-1); // heap, ≈ Rc<T> of Rust std::shared_ptr<const T> ptrm_heap_multiple_owner_thread_unsafe_valc = std::make_shared<T>(-1); // heap, ≈ Rc<Cell<T>> of Rust std::shared_ptr<T> ptrm_heap_multiple_owner_thread_unsafe_valm = std::make_shared<T>(-1); // heap, ≈ Rc<RefCell<V>> of Rust std::shared_ptr<V> ptrm_heap_multiple_owner_thread_unsafe_refm = std::make_shared<V>(V()); ptrm_heap_multiple_owner_thread_unsafe_refm->push_back(-2000); // single reader/writer control object, ≈ Mutex<T> without <T> of Rust std::mutex mutex_1rw_thread_safe_controller; // multiple reader/single writer control object, ≈ RwLock<T> without <T> of Rust std::shared_mutex mutex_mr1w_thread_safe_controller; }
// Rust; Rc:=Reference Counted, Arc:=Automatically Reference Counted use std:: { rc::Rc , sync::{Arc, Mutex, RwLock} , cell::{ Cell, RefCell } }; fn main() { type T = i32; type V = Vec<T>; // mutable value let mut valm: T = 1; let mut valm_the_other = 2; // const ref -> mutable value let refc_valm: &mut T = &mut valm; *refc_valm = 11; // const ptr -> const value let refc_valc: &T = &valm; println!("{} <-- It's a const value via const ref.", refc_valc); // mutable ptr -> mutable value; deref-ptr is an unsafe operation let mut ptrm_valm: *mut T = &mut valm as *mut T; unsafe { *ptrm_valm = 21 }; ptrm_valm = &mut valm_the_other as &mut T; unsafe { *ptrm_valm = 22 }; // const ptr -> mutable value let ptrc_valm: *mut T = &mut valm as *mut i32; unsafe { *ptrc_valm = 31 }; // const ptr -> const value let ptrc_valc: *const T = &valm as *const i32; println!("{:?} <-- It's a const value via const ptr.", ptrc_valc); // heap, ≈ new of C++ let mut ptrm_heap_static_lifetime: *mut T = unsafe{ std::alloc::alloc( std::alloc::Layout::new::<T>() ) } as *mut T; unsafe { *ptrm_heap_static_lifetime = -10 }; // heap, ≈ std::unique_ptr<T> of C++, deref -> mutable value let mut ptrm_heap_single_owner_valm: Box<T> = Box::<T>::new(-1); *ptrm_heap_single_owner_valm = -100; // heap, ≈ std::unique_ptr<const T> of C++, deref -> mutable value let ptrm_heap_single_owner_valc: Box<T> = Box::<T>::new(-1); // heap, ≈ std::shared_ptr<const T> of C++, deref -> const value let ptrm_heap_multiple_owner_thread_unsafe_valc: Rc<T> = Rc::<T>::new(-1); // heap, ≈ std::shared_ptr<T> + std::mutex of C++, deref -> mutable value let ptrm_heap_multiple_owner_thread_unsafe_valm: Rc<Cell<T>> = Rc::new(Cell::<T>::new(-1)); ptrm_heap_multiple_owner_thread_unsafe_valm.set( -200 ); // heap, ≈ std::shared_ptr<T> + std::mutex of C++, deref -> mutable ref let ptrm_heap_multiple_owner_thread_unsafe_refm: Rc<RefCell<V>> = Rc::new(RefCell::new(V::new())); ptrm_heap_multiple_owner_thread_unsafe_refm.borrow_mut().push( -2000 ); // heap, ≈ std::shared_ptr<const T> of C++, deref -> const value let ptrm_heap_multiple_owner_thread_unsafe_valc: Arc<T> = Arc::<T>::new(-1); // heap, ≈ std::shared_ptr<T> + std::shared_mutex of C++, deref -> mutable value let ptrm_heap_multiple_owner_thread_unsafe_valm: Arc<Mutex<T>> = Arc::new(Mutex::<T>::new(-1)); *ptrm_heap_multiple_owner_thread_unsafe_valm.lock().unwrap() = -200; // heap, ≈ std::shared_ptr<T> + std::shared_mutex of C++, deref -> mutable ref let ptrm_heap_multiple_owner_thread_unsafe_refm: Arc<RwLock<T>> = Arc::new(RwLock::<T>::new(-1)); { let r0 = *ptrm_heap_multiple_owner_thread_unsafe_refm.read().unwrap(); let r1 = *ptrm_heap_multiple_owner_thread_unsafe_refm.read().unwrap(); println!("r0 = {:?}, r1 = {:?}", r0, r1); // drop(≈release) r0, r1 then it will be writable in the out of this scope } *ptrm_heap_multiple_owner_thread_unsafe_refm.write().unwrap() = -3000; }
参考
- rust — Rustのセルと参照カウントタイプについての全体的な説明が必要
- Unsafe Rust - The Rust Programming Language
- RefCell<T>と内部可変性パターン - The Rust Programming Language
- Arc<Mutex<T>>という形はデザインパターン - Rustコトハジメ
- brughdiggity comments on Hey Rustaceans! Got an easy question? Ask here (22/2017)!
- Explicate what "Rc" and "Arc" stand for. by ucarion · Pull Request #42419 · rust-lang/rust · GitHub
- Rust RefCell(T) - javatpoint
- Rust book 勉強会 #7 - slideship.com