use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let data = Rc::new(RefCell::new(vec![1, 2, 3]));
let data_clone = Rc::clone(&data);
data_clone.borrow_mut().push(4);
println!("{:?}", data.borrow());
}
When you need multiple ownership without threads, Rc<T> (reference counted) is the answer. It tracks the number of owners at runtime and frees the data when the count reaches zero. For mutability, combine it with RefCell<T>, which enforces borrowing rules at runtime instead of compile time. RefCell::borrow() and RefCell::borrow_mut() return guards that panic if the rules are violated. I use Rc<RefCell<T>> sparingly, mostly for graph-like data structures or observer patterns where compile-time borrow checking is too restrictive. The downside is runtime overhead and potential panics, so I prefer compile-time solutions when possible. This pattern only works in single-threaded contexts; for threads, use Arc<Mutex<T>>.
Related snips
struct Config<'a> {
name: &'a str,
value: &'a str,
}
fn parse_config(line: &str) -> Config {
Lifetime annotations for flexible borrowing in structs
use crossbeam::channel::unbounded;
use std::thread;
fn main() {
let (tx, rx) = unbounded();
Crossbeam for advanced concurrent data structures
use tracing::{info, instrument};
#[instrument]
fn process_request(user_id: u64) {
info!(user_id, "Processing request");
// Work happens here
tracing for structured logging and distributed tracing
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
Channels (mpsc) for message passing between threads
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about)]
struct Args {
#[arg(short, long)]
clap for CLI argument parsing with derive macros
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("Called {}", stringify!($func_name));
}
};
Declarative macros (macro_rules!) for code generation
Share this code
Here's the card — post it anywhere.