0

I want to have multiple data containers for the same object with the same reference (pointer), and can't figure out how to achieve that in Rust. Go can simply use reference to the object as below:

type container struct {
    id     int
    status string
}

m1 := make(map[int]*container)
m2 := make(map[int]*container)

c := &container{id: 1, status: "test"}
m1[1] = c
m2[1] = c

c.status = "changed"

fmt.Println(m1[1]) // &{1 changed}
fmt.Println(m2[1]) // &{1 changed}

I tried to use Box to allocate it in heap but cannot compile...

use std::{cell::Cell, collections::HashMap};

fn main() {
    let mut m1: HashMap<i32, Box<Container>> = HashMap::new();
    let mut m2: HashMap<i32, Box<Container>> = HashMap::new();

    let mut c = Box::new(Container {
        id: 1,
        status: Cell::new(String::from("test")),
    });
    m1.insert(1, c);
    m2.insert(1, c);
    c.status.set("changed".to_string());
}

struct Container {
    id: i32,
    status: Cell<String>,
}

I used Cell to allow interior mutability but not relevant to this question... I want to learn how to create this Container object once, and allocate it on heap, and share the object across different data containers.

1 Answers1

2

Instead of Box, you need to use Rc or Arc depending on your sync needs:

use std::rc::Rc;
use std::{cell::Cell, collections::HashMap};

fn main() {
    let mut m1: HashMap<i32, Rc<Container>> = HashMap::new();
    let mut m2: HashMap<i32, Rc<Container>> = HashMap::new();

    let c = Rc::new(Container {
        id: 1,
        status: Cell::new(String::from("test")),
    });
    m1.insert(1, Rc::clone(&c));
    m2.insert(1, Rc::clone(&c));
    c.status.set("changed".to_string());
}

struct Container {
    id: i32,
    status: Cell<String>,
}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • Thanks! I was also reading https://stackoverflow.com/questions/49377231/when-to-use-rc-vs-box and had an impression that `Rc` is for immutable objects which makes sense since the only mutable component is the interior field. Would there be any case one may prefer `RefCell` to `Rc` in this case? – ldanfrustdsbflqbsdeedrustdf May 23 '22 at 18:30
  • RefCell is not a replacement for Rc, actually you would find them nested usually (`Rc`) – Netwave May 23 '22 at 18:50
  • @idanfrustdsbflqbsdeedrustdf `RefCell` and `Rc` serve different purposes. `Rc` permits shared ownership, and `RefCell` provides runtime borrow checking. For your purpose, you either want `Rc>` or `Rc`. – Aiden4 May 23 '22 at 19:11