Rust learning – when to put data on the heap

Time:2021-6-10

When to put data on the heap

Cognitive ownership, Life cycle and reference validity, Smart pointerThese three chapters are related. Ownership and life cycle ensure the validity of data. Smart pointer data is stored on the heap and the pointer is on the stack.

Suggestions in the book

  • When there is a type of unknown size at compile time, and you want to use the type value in a context that requires an exact size
  • When there is a large amount of data and you want to transfer ownership without copying it
  • When you want to have a value and only care about whether its type implements a specific trait rather than its specific type

I understand that if the user-defined structure data is large or the size can be determined at run time, it is recommended to put it in the heap when multiple different scopes need to share data.VecThe data in is put in the heap.

Usage scenarios

useRustWhen developing a small tool, it is often calledcloneMethod. After reading the file data, parsing creates a structure, and then puts it into aVecYou need to get some data in one place, modify some values, and then keep them in anotherVecIn the middle. At this timeVecThe value modification data is taken out from,cloneA preservation, although to the needs. But I think about twoVecIt’s all the same data, just twoVecIf the number is different, you need to keep the objects in the heap.

//Multiple C objects in the scene need to share a and B data, and they need to have modify permission for a
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct A {
    name: String,
}
impl Drop for A {
    fn drop(&mut self) {
        println!("A drop: {}", self.name);
    }
}

impl Drop for B {
    fn drop(&mut self) {
        println!("B drop: {}", self.name);
    }
}
#[derive(Debug)]
struct B {
    name: String,
}
#[derive(Debug)]
struct C {
    list_a: Vec<Rc<RefCell<A>>>,
    list_b: Vec<Rc<B>>,
}

#[test]
fn test_rc() {
    let mut c = C {
        list_a: Vec::new(),
        list_b: Vec::new(),
    };
    let a = Rc::new(RefCell::new(A {
        name: String::from("zhang"),
    }));
    let b = Rc::new(B {
        name: String::from("wu"),
    });
    println!("a ptr: {:p}", a);
    println!("b ptr: {:p}", b);
    c.list_a.push(a);
    c.list_b.push(b);
    f2(&c);
    c.list_b.push(Rc::new(B {
        name: String::from("li"),
    }));
    println!("{:?}", c);
}

fn f2(c: &C) {
    let mut c2 = C {
        list_a: Vec::new(),
        list_b: Vec::new(),
    };

    for c1a in c.list_a.iter() {
        println!("a ptr: {:p}", *c1a);
        let mut a = (*c1a).borrow_mut();
        a. Name = string:: from ("I changed");
        c2.list_a.push(Rc::clone(c1a));
    }
    for c1b in c.list_b.iter() {
        println!("b ptr: {:p}", *c1b);
        c2.list_b.push(Rc::clone(c1b));
    }
    println!("{:?}", c2);
}

There are two codes aboveCIt’s all pointing to the pileAandB, inf2Revised inCInAData, and put the pointer in the secondCIn the middle. In the code run results can be foundAandBnonecloneThe action of twoCObject is the same piece of data. The data here does not support multi line sharing, so it needs to be shared under multi thread, and it needs to be usedMutex<T>andArc<T>