Reputation: 23
I get a confusing compilation error when:
Here is a code example:
fn main()
{
let mut v = Vec::<(int,String)>::new();
v.push((3, String::new()));
let u = v[0].val0();
}
Which yields the following error:
error: cannot move out of dereference (dereference is implicit, due to indexing)
I thought I had a reasonable understanding of ownership, borrowing, references and lifetimes, but I still do not get this error. Why does it happen ?
Update:
Thank you for your answers Vladimir and Levans.
Vladimir, I will use the tuple indexing syntax, as advised, but I was mostly interested in the "why". Why can't something so simple work ?
As Levans said, the definition of val0 is:
fn val0(self) -> A
I managed to simplify my example further:
fn main()
{
let t : (int, String) = (3, String::new());
let u = t.val0();
let v = t.val1();
}
Which gets me the following errors :
main.rs:8:13: 8:14 error: use of moved value: `t`
main.rs:8 let v = t.val1();
main.rs:7:13: 7:14 note: `t` moved here because it has type `(int,collections::string::String)`, which is non-copyable (perhaps you meant to use clone()?)
main.rs:7 let u = t.val0();
This is what I was looking for. What I was missing is that complex types cannot be copied by value. So instead, they are moved to the scope of the function which is called.
Note that the following does work, because (int,int) is not a complex type:
fn main()
{
let t : (int, int) = (3, 4);
let u = t.val0();
let v = t.val1();
}
I still think having more information in the error message of the original example (with Vec) would be very helpful.
Upvotes: 2
Views: 4680
Reputation: 128001
With recent Rust compiler you don't need valX()
/refX()
methods, you can use tuple indexing syntax. I'm actually surprised that they are not deprecated (probably because tuple indexing is still behind a feature gate). Tuple indexing looks like this:
#![feature(tuple_indexing)]
fn main() {
let mut v = Vec::<(int,String)>::new();
v.push((3, String::new()));
let u = v[0].0; // use 1st (with zero-based indices) field of a tuple
println!("{}", u);
}
This program, fortunately, will work because accessing tuple fields is like accessing fields in a regular struct - it doesn't need to take ownership of the whole struct and it supports partial moves. In this particular case the first field type is implicitly copyable, so you can just access it and it will be copied.
Upvotes: 4
Reputation: 15002
The prototype of val0()
is :
fn val0(self) -> A
as you see, it consumes the tuple to unwrap the first value. Thus, when you call it on v[0]
, it effectively tries to move the tuple into val0()
's scope, which is forbidden as the tuple is owned by your Vec.
You probably want to use ref0
, which gives you a reference to the first item, without consuming the tuple:
fn ref0(&'a self) -> &'a A
Upvotes: 3