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.