According to "The Rust Programming Language" ch05-03 Here’s how it works: When you call a method with object.something() , Rust automatically adds in & , &mut , or * so that object matches the signature of the method. In other words, the following are the same:
My question is about this code
let value = Rc::new(RefCell::new(5));
*value.borrow_mut() += 10;
I can understand why value.borrow_mut() will automatic compile to (*value).borrow_mut()
But why I should add * before value.borrow_mut() for the next add operation
This is the docs about += operator
fn add_assign(&mut self, rhs: Rhs);
In my understanding *value.borrow_mut() += 10; equals to
*value.borrow_mut().add_assign(10);
It still call a method,so why the compiler doesn't automatic add * before value.borrow_mut()?
It just like this example
let mut a = 3;
let mut b = &mut a;
*b += 1;
// Why B should add * before
If I am wrong, please point it out.
Thanks for your answer
I think it's just that the auto deref works for method calls. You are confusing operator syntax and method calls, even though internally '+=' is dispatched to add_assign(), I think the book makes it clear that this is something that only works with method calls (I guess the compiler doesn't infer directly from the operator syntax). Also I don't think &mut a implements AddAssign here, these are are only implemented for primitive types themselves.
there are two kinds of things going on here, which are very different.
Method calls
mehtods calls are of the form expr.method(args), and they do add &, &mut, and * automatically until they find a type match for the method call.
The XAssign operators
these operators are used as follows place X= expr;. a place expression is a kind of expression one can assign to. neither the XAssign operators no the regular binary operator insert any &, &mut, or * to find the correct type. they only accept the type as is
when you implement the XAssign operator, you do write fn x_assign(&mut self, rhs: Rhs), but when you use them as operator, it will add the &mut. so a += b becomes AddAssign::add_assigned(&mut a, b) !
this is because it works best with local variables.
so a += b only works if A : AddAssign<B>, which is the cleanest.
value.borrow_mut() is a &mut i32, so you must convert it t an i32 to use += on it
that is wrong *value.borrow_mut() += 10;
equals to
And I want to ask
Is it only expr.method(args) , compiler will add & , &mut , and * automatically until they find a type match for the method call.
Is there any syntactic sugar can do the same thing?
Thanks
not in general, but on certain coercion sites rust can implicitly transform one reference into another as if through similar inserts. most common being function arguments and function output :
fn works1<'a>(x : &&&'a str) -> &'a str {
x
}
fn works2<'a>(x : &&&'a String) -> &'a str {
x
}
fn works3<'a>(x : &'a mut &'a mut &'a mut String) -> &'a mut str {
x
}
fn works4<'a>(x : &'a mut Box<&'a mut String>) -> &'a mut str {
x
}
fn doesntwork1<'a>(x : Box<&'a mut &'a mut String>) -> &'a mut str {
&mut x // doesn't work because `Box` isn't a reference
// *x would work
// the compiler adivises using `&mut x`. while this would allow the coercion,
// the lifetimes wouldn't work out and the function wouldn't compile
}
fn doesntwork2(x : &&&u8) -> u8 {
x // doesn't work because `u8` isn't a reference
// only ***x would work
}
note that these can only remove reference layers, not add more
it is because the documentation is sloppily phrased. Operators aren't desugarings to other Rust source code; there are cases where the operator resolution doesn't correspond to any desugaring AFAIK.
Or in short: don't take statements about Rust expressions being "equivalent" too literally.