0

I'm just learning Rust and run into an interesting phenomenon using Arc. With Arc, let's say I wrap a vec with arc, I can access that vec just as it was a normal vec without changing my code. For example:

let arc = Arc::new(vec![0,1,2,3]);
    
for x in arc.iter() {
    print!("{}", x);
}

// I can even call `len` as if it was a normal vector
println!("{}", arc.len());

I have some custom code which I am wrapping a vector and adding some custom logic on top of it.

struct Wrapper {
    underlying: Vec<i32>,
    my_custom_field_for_custom_logic: bool
}

// my wrapper
let wrap = Wrapper {
    underlying: vec![0,1,2,3],
    my_custom_field_for_custom_logic: true
};

for x in wrap.underlying.iter() {
    println!("{}", x);
}

For my structure, I have to use a special field called underlying to access the underlying vector.

I looked into Arc's source code and found this:

pub struct Arc<T: ?Sized> {
    ptr: NonNull<ArcInner<T>>,
    phantom: PhantomData<ArcInner<T>>,
}

Essentially it has fields for underlying data as well. I'm new to rust, so the rest of the code goes way over my head.

So my question is essentially how can I make my Wrapper structure behave like Arc, in the sense that I can directly call vector methods (or methods of the underlying data) without accessing a special field.

Not a big deal, but I would like to know how it's done.

l3utterfly
  • 2,106
  • 4
  • 32
  • 58
  • Correct me if I'm wrong here: 1. Arc is not using the "newtype" pattern as far as I can tell, so does Deref apply here? 2. If Deref applies here, so Arc is implementing deref to access the underlying type, i thought that was bad practice? – l3utterfly Aug 13 '21 at 06:04
  • 1
    Yes `Deref` can be used here. `Deref` is not always bad practice, it's a very useful tool, but for dedicated types. `Arc` is one of the "smart reference" types, it's used explicitly to work as a reference, so it makes sense to implement `Deref`. – Denys Séguret Aug 13 '21 at 06:12
  • Ahh, that's good to know. Thank you. – l3utterfly Aug 13 '21 at 06:14
  • 1
    In addition to the linked QA, The [documentation for Deref](https://doc.rust-lang.org/std/ops/trait.Deref.html) has now this to say, in bold: **"Deref should only be implemented for smart pointers to avoid confusion."** – Denys Séguret Aug 13 '21 at 06:18
  • @DenysSéguret Do you know when that line was added? Deref is commonly implemented for non-pointer types even in std. For example it's implemented for owned counterparts of slice types: String, Vec, PathBuf etc. and I routinely implement it for similar types. – Peter Hall Aug 13 '21 at 10:09
  • @PeterHall I'd say `String` and `PathBuf` can be considered smart pointers for `str` and `OsStr`, respectively, while `Vec` is also a smart pointer for a slice, `[T]`, so the statement is still mostly correct. – Filipe Rodrigues Aug 13 '21 at 18:23
  • A lot of things can be considered "mostly correct" if you stretch out their meanings :) – Peter Hall Aug 13 '21 at 20:52

0 Answers0