|
|
|
|
|
by fredmorcos
3738 days ago
|
|
In this video[0] on Rust, in this example I was unable to directly tell whether the Vec structure is being copied to the take() function. If ownership is being handed over, why is a copy being made? And if a copy really isn't being made, then why aren't the function signature and the calling site reflecting that? I hope I am making any sense... Please tell me if I should try to rephrase, or if I am in need of clarification on the subject. (BTW, this is also something I really dislike about C++, two function calls that look exactly the same, foo(x) and bar(x), could either be pass by value or pass by reference: you have to go dig up the function signatures to figure that out). [0] https://youtu.be/O5vzLKg7y-k?t=1110 |
|
Moving is always a memcpy. There's no way to change this behavior, so you can always know that it's true. But with a Vec, there's a subtlety: the Vec itself is three words: a pointer to the heap, a length, and a capacity. So when I say that the Vec is memcpy'd, I mean literally those three things. It doesn't try to follow the pointer and copy the data that it points to.
Incidentally, that pointer is why we say that it moves: because two copies of the Vec structure itself would mean an aliased pointer to the heap, the compiler doesn't allow the use of the older binding after take() is called.
For simpler types, like integers:
they implement a trait called Copy. This means that when you call take, the i32 is copied, in the same fashion that the Vec was copied. The only difference is that there's no problem with having these two copies, as an i32 is, well, just an i32. So the compiler won't prevent the use of the binding outside the function like it would with a non-Copy type.References are like pointers, but with the extra static checking that Rust does.
References also implement Copy, and so when you pass a reference to a Vec to this function, the same thing happens as in the i32 case. The reference itself gets copied.This is sort of a long-winded way of saying that Rust is "pass by value", not "pass by reference." Some people like to call this "pass reference by value", since while it's always pass by value, references are themselves values.
What if we _did_ want to make a full copy of the Vec, including its elements? For that, we have to use the .clone() method.
Now, v and v1 will be full, independent copies of the same thing. In other words, if you don't see .clone(), it will never be a deep copy. You can always see, syntactically, when you're making a possibly expensive copy of something.Does that help? I'm happy to elaborate further.