I have a hard time understanding when to use the asterisk operator for dereferencing and when can I omit it.
fn main() { a(); b(); c(); d(); }
fn a() {
let v = 1;
let x = &v;
println!("a {}", *x);
println!("a {}", 1 + *x);
}
fn b() {
let v = 1;
let x = &v;
println!("b {}", x);
println!("b {}", 1 + x);
}
fn c() {
let mut v = 1;
let mut x = &mut v;
println!("c {}", *x);
println!("c {}", 1 + *x);
}
fn d() {
let mut v = 1;
let mut x = &mut v;
println!("d {}", x);
println!("d {}", 1 + x); // error
}
The above code sample almost compiles except the last statement where I add one to the the mutable reference x. There I get this error:
the trait bound `_: std::ops::Add<&mut _>` is not satisfied [E0277]
Anywhere else both asterisk and non-asterisk versions are valid and give expected results.
You can only add types for which the operator is defined by implementing the Add trait. In both examples where you do 1 + *x, the type of *x is i32 and indeed i32 + i32 is defined. For convenience there is also an implementation of i32 + &i32 (and &i32 + i32 and &i32 + &i32) which makes b work, but this is just for the specific case of one immutable reference, it doesn't extend to, say &&i32 or &mut i32. That's why d does not work.
Related
I am trying to write a mem::swap function without using any std lib functions. i am totally new to rust and still trying to make sense of how to use rust language.
below is my code
fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
unsafe {
// Give ourselves some scratch space to work with
let mut t: &mut T = y;
y = x;
x = t;
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
let mut t = Box::new(0);
swap(&mut x, &mut y);
}
and i am facing below error
error: lifetime may not live long enough
--> src/main.rs:4:29
|
1 | fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
| - - let's call the lifetime of this reference `'2`
| |
| let's call the lifetime of this reference `'1`
...
4 | let mut t: &mut T = y;
| ^ assignment requires that `'2` must outlive `'1`
|
help: consider introducing a named lifetime parameter
|
1 | fn swap<'a, T: std::fmt::Display>(x: &'a mut T, y: &'a mut T) {
| +++ ++ ++
what does 'lifetime may not live long enough' mean ?
is there a simple way to write mem::swap code in rust ?
You need to Copy the data. The reference you're using is useless for this purpose. You need to actually alter what both x and y reference.
For example:
fn swap<T>(a: &mut T, b: &mut T) where T : Copy {
(*a,*b) = (*b, *a)
}
fn main() {
let mut a = 1;
let mut b = 2;
swap(&mut a,&mut b);
println!("a={}, b={}", a, b);
}
If you set up the conditions here, it's really a one-liner, Rust will figure out the "temporary" stuff for you. In fact, having a function to do this is actually kind of overkill, since you can just do that single line anywhere in your code as you would normally.
Maybe you want to optimize this around boxed values, taking Box<T> as an argument instead, in which case you could swap references within the box instead of copying, but that's a specialization.
How about using core::ptr::swap to swap raw pointers *mut T.
use core::ptr::swap;
fn custom_swap<T>(x: &mut T, y: &mut T) {
unsafe {
(x as *mut T).swap(y as *mut T);
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
println!("x={}, y={}", x, y);
custom_swap(&mut x, &mut y);
println!("x={}, y={}", x, y);
}
output
Hello, world!
x=5, y=42
x=42, y=5
When pattern-matching, you can specify that you'd like to get a mutable reference to the contained value by using ref mut:
let mut score = Some(42);
if let Some(ref mut s) = score {
&mut s;
}
However, the inner value is not mutable:
error[E0596]: cannot borrow immutable local variable `s` as mutable
--> src/main.rs:4:14
|
4 | &mut s;
| ^
| |
| cannot reborrow mutably
| try removing `&mut` here
I tried to add in another mut, but that was not valid:
if let Some(mut ref mut s) = score {
&mut s;
}
error: the order of `mut` and `ref` is incorrect
--> src/main.rs:3:17
|
3 | if let Some(mut ref mut s) = score {
| ^^^^^^^ help: try switching the order: `ref mut`
error: expected identifier, found keyword `mut`
--> src/main.rs:3:25
|
3 | if let Some(mut ref mut s) = score {
| ^^^ expected identifier, found keyword
error: expected one of `)`, `,`, or `#`, found `s`
--> src/main.rs:3:29
|
3 | if let Some(mut ref mut s) = score {
| ^ expected one of `)`, `,`, or `#` here
Not a direct answer, but possible workarounds
Create an intermediate variable
if let Some(ref mut s) = score {
let mut s = s;
&mut s;
}
#[derive(Debug)]
struct X;
enum Foo<T> {
Bar(T),
_Baz,
}
fn main() {
let mut score = Foo::Bar(X);
if let Foo::Bar(ref mut s) = score {
//let x = s;
//println!("{:?}", **x); ! not possible
let x = &mut &mut *s; // &mut &mut X
println!("{:?}", **x);
}
}
For Option specifically
if let Some(ref mut s) = score.as_mut() {
s; //:&mut &mut i32
}
if let Some(mut s) = score.as_mut() {
&mut s;
}
Below code may give an idea for the possible solution to the problem. It's just a sample & testable code to provide a tiny example that aimed at the issue. Of course it may not cover the whole intents and purposes.
fn main() {
let mut score = Some(42i32);
let res = if let Some(41) = score {
println!("41 is matched");
1i32
} else if let Some(ref mut s) = score { //&mut score {
//let mut s2 = s;
//println!("s: {:#?}", s);
test(&mut &mut *s); // This part may be like this for borrowing
//println!("s: {:#?}", s);
1i32
} else {
0i32
};
//println!("Result: {:#?}", score);
assert_eq!(res, 1i32);
}
fn test(ref mut s: &mut &mut i32) -> i32 {
//let mut s2 = s;
return test2(&mut *s);
}
fn test2(n: &mut i32) -> i32 {
*n += 1;
//println!("Value: {}", *(*n));
return *n;
}
Live Version: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7c3e7e1ee712a31f74b201149365035f
Gist Link: https://gist.github.com/7c3e7e1ee712a31f74b201149365035f
I'm learning about ownership and borrowing.
The difference between borrow1 and borrow2 is the usage of & while printing in borrow2:
fn borrow1(v: &Vec<i32>) {
println!("{}", &v[10] + &v[12]);
}
fn borrow2(v: &Vec<i32>) {
println!("{}", v[10] + v[12]);
}
fn main() {
let mut v = Vec::new();
for i in 1..1000 {
v.push(i);
}
borrow1(&v);
println!("still own v {} , {}", v[0], v[1]);
borrow2(&v);
println!("still own v {} , {}", v[0], v[1]);
}
Why do they give the same output, even though borrow1 doesn't have &?
The index operator ([]) for a Vec<T> returns a T. In this case, that's an i32. Thus v[0] returns an i32 and &v[0] returns an &i32:
let a: i32 = v[0];
let b: &i32 = &v[0];
v[0] only works because i32 implements Copy.
i32 has implemented Add for both the (left-hand side, right-hand-side) pairs of (i32, i32) and (&i32, &i32). The two implementations add values in the same way, so you get the same result.
See also:
What is the return type of the indexing operation on a slice?
Understanding (automatic?) Deref/coercion when adding references and values of numbers
I have found a case where manually inlining a function changes the way the borrow-checker treats it, such that it no longer compiles. Presumably it is relying on the information in the function signature. How can I provide this information in the inlined version?
How I think it's working
Let 'a and 'b be lifetimes with 'a shorter than 'b (which can be written 'b: 'a).
Suppose I have a p: &'b mut f32. I can borrow p briefly (with &mut p) to obtain q: &'a mut &'b mut f32.
Have I correctly understood that &'a mut &'b mut f32 is equivalent to &'a mut &'a mut f32 because 'b: 'a?
I can then dereference q (with *q) to obtain r: &'a mut f32. I can write to the f32 via r (with *r = something), and I can later (outside lifetime 'a) read back the value via p (with *p).
With a function call
Here is some working code that I think uses the above sequence:
fn reborrow<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = reborrow(q);
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
(Replacing *q with q in the body of reborrow() also works, because Rust inserts the necessary dereference if it is missing).
Manually inlined
If I manually inline the reborrow() call, it no longer compiles:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = *q; <-- ERROR REPORTED HERE.
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
error[E0507]: cannot move out of borrowed content
Who took away my toys? What is the type inference thinking/missing?
Can I annotate the let binding somehow to make the compiler infer the same types as in the previous version?
Some other attempts
Here's another version that works, but which doesn't define the name r:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
**q = 2.718;
}
assert_eq!(*p, 2.718);
}
Here's a work-around that defines the name r and works, but does not use the same sequence of borrows and dereferences:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = &mut **q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
I made a playground combining all four versions.
The obvious solution works, as one could expect:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
It seems relatively intuitive and is what I would expect a newcomer to end up with.
If you start thinking about it, however, it will not make sense. As described, it looks like:
let r: &mut f32 = p; moves out of p
and yet we use p later in assert_eq!(*p, 2.718);
A reasonable explanation would be that p is Copy, however it's not1!
The answer is that, implicitly, Rust is performing a re-borrowing behind the scenes. That is, the explicit code is:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = &mut *p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
We can check this by attempting to read p after re-borrowing it, and check the compiler error:
error[E0502]: cannot borrow `p` as immutable because `*p` is also borrowed as mutable
--> <anon>:6:24
|
5 | let r: &mut f32 = p;
| - mutable borrow occurs here
6 | println!("{}", p);
| ^ immutable borrow occurs here
7 | *r = 2.718;
8 | }
| - mutable borrow ends here
error: aborting due to previous error
Which confirms that p is indeed only borrowed mutably, and not moved, cloned or copied.
1 A mutable reference cannot be Copy or even Clone as it would violate the Aliasing XOR Mutability principle which underpins Rust safety.
I can't possibly begin to explain this, but you can do a similar trick as the implicit dereference and say that r is &mut f32:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r: &mut f32 = q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
Since it's possible to pass a mutable reference to a vector around (without causing moves), how can an Option<reference> be passed to functions multiple times without causing borrow checking errors?
This simple example just shows what happens when an Option<&mut Vec<usize>> is passed multiple times to a function:
fn maybe_push(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(ref mut v) = v_option.as_mut() {
for i in 0..10 {
v.push(i);
c += i;
}
}
return c;
}
fn maybe_push_multi(v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
c += maybe_push(v_option);
c += maybe_push(v_option);
c += maybe_push(None);
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
let v_option = Some(&mut v);
println!("{}", maybe_push_multi(v_option));
}
(Playground)
Gives the error:
error[E0382]: use of moved value: `v_option`
--> <anon>:17:21
|
16 | c += maybe_push(v_option);
| -------- value moved here
17 | c += maybe_push(v_option);
| ^^^^^^^^ value used here after move
|
= note: move occurs because `v_option` has type `std::option::Option<&mut std::vec::Vec<usize>>`, which does not implement the `Copy` trait
You can pass the Option by reference too, if you don't want it moved into the function.
fn maybe_push(mut v_option: &mut Option<&mut Vec<usize>>) -> usize
// ...
maybe_push_twice(&mut v_option);
Then replace:
maybe_push(None);
With:
maybe_push(&mut None);
You can destructure the Option with a match expression and then create a new Option value for every call of the function maybe_push():
fn maybe_push_twice(v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
match v_option {
Some(v) => {
c += maybe_push(Some(v));
c += maybe_push(Some(v));
}
None => {
c += maybe_push(None);
c += maybe_push(None);
}
};
return c;
}
Here is a more convenient way:
fn maybe_push_twice(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
c += maybe_push(v_option.as_mut().map(|x| &mut **x));
c += maybe_push(v_option);
return c;
}
You can use a trait instead of a macro:
trait RefMut<T> {
fn ref_mut(&mut self) -> Option<&mut T>;
}
impl<'t, T> RefMut<T> for Option<&'t mut T>{
#[inline]
fn ref_mut(&mut self) -> Option<&mut T>{
self.as_mut().map(|x| &mut**x)
}
}
fn maybe_push_twice(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
c += maybe_push(v_option.ref_mut());
c += maybe_push(v_option);
return c;
}
As of 1.40.0, you can use Option::as_deref_mut.
fn maybe_push_twice(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
c += maybe_push(v_option.as_deref_mut());
c += maybe_push(v_option);
c
}
Here is a playground modified from the original playground.