1

Most of the dereferencing code you see out there in the docs related to Rust show the use of integers. But integers are a special data structure. I am more interested in structs/objects and how they are dereferenced. I am looking for examples on dereferencing involving structs basically, which leads to the question here.

For example, you see some of this in the stdlib codebase:

// borrow.rs
impl<T: ?Sized + Hash, A: Allocator> Hash for Box<T, A> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}

// rc.rs
impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
  fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
      (**self).partial_cmp(&**other)
  }
}

First, why is the double ** needed in these two cases? Why in this case do we need to dereference self before calling the method, why don't we always dereference self when calling a method?

Then you have more obvious cases like this *f == Foo, this is a case beyond integers:

fn test_iter_zero_sized() {
    let mut v = vec![Foo, Foo, Foo];
    assert_eq!(v.len(), 3);
    let mut cnt = 0;

    for f in &v {
        assert!(*f == Foo);
        cnt += 1;
    }
    //...
}

But then you have like this match *self:

// borrow.rs
impl<B: ?Sized + ToOwned> Clone for Cow<'_, B> {
    fn clone(&self) -> Self {
        match *self {
            Borrowed(b) => Borrowed(b),
            Owned(ref o) => {
                let b: &B = o.borrow();
                Owned(b.to_owned())
            }
        }
    }
}

// mod.rs
impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        match *unsafe { self.inner() } {
            Flavor::Oneshot(ref p) => p.drop_chan(),
            Flavor::Stream(ref p) => p.drop_chan(),
            Flavor::Shared(ref p) => p.drop_chan(),
            Flavor::Sync(..) => unreachable!(),
        }
    }
}

Why is match *self needed? Why not just match self? (I know it's a reference as defined by the parameter &self, but you don't call methods like *self.method())

The main reason I ask is because all the method calls are not dereferenced, like:

o.borrow()
p.drop_chan()

where o and p are defined as ref o and ref p above. Other random examples of method calling is slice.len() or buf.into_box(slice.len()).assume_init():

impl<T: Copy> From<&[T]> for Box<[T]> {
  fn from(slice: &[T]) -> Box<[T]> {
      let len = slice.len();
      let buf = RawVec::with_capacity(len);
      unsafe {
          ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
          buf.into_box(slice.len()).assume_init()
      }
  }
}

Are these really syntactic sugar for something like this?

(*slice).len()
(*(*buf).into_box((*slice).len())).assume_init()

You see it all the time with self. Well, besides &**self (which I still have yet to understand):

impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B>
where
    B: ToOwned,
    <B as ToOwned>::Owned: 'a,
{
    fn borrow(&self) -> &B {
        &**self
    }
}

But beside the point. You see self.method() like this self.as_bytes().into():

// boxed.rs
impl Clone for Box<str> {
    fn clone(&self) -> Self {
        // this makes a copy of the data
        let buf: Box<[u8]> = self.as_bytes().into();
        unsafe { from_boxed_utf8_unchecked(buf) }
    }
}

So is that really just syntactic sugar for something else?

FYI, I don't have a deep practical understanding of Rust yet, I am studying it to build a programming language (amongst studying other programming languages), but I have deeply read most of the docs on Rust so far.

Herohtar
  • 5,347
  • 4
  • 31
  • 41
Lance
  • 75,200
  • 93
  • 289
  • 503
  • 2
    You've included a lot of code and questions but most can be addressed by [What are Rust's exact auto-dereferencing rules?](https://stackoverflow.com/q/28519997) – kmdreko Feb 26 '22 at 06:16
  • Also, `match *self` is not necessary - you could drop the `ref` and use `match self`, it would work just as well. (Older Rust was a bit more literal and required either `match *self` or putting `&` in front of every match arm.) – user4815162342 Feb 26 '22 at 07:44
  • That doesn't really answer the question: so are method calls sugared or not? It's interesting though! Thanks for sharing. – Lance Feb 26 '22 at 09:36

0 Answers0