Ownership and Moves
Example of ownership in C/C++:
s
itself is on stack. s
owns a buffer on heap.
Assignment in Python vs C++:
s
, t
and u
actually points to the same PyListObject
.
s
, t
and u
each points to a new copy of the list.
Ownership
A variable owns its value. When control leaves the block in which the variable is declared, the variable is dropped, so its value is dropped along with it.
Box
serves as another example of ownership. A Box<T>
is a pointer to a value of type T
stored on the heap. Calling Box::new(v)
allocates some heap space, moves the value v
into it, and returns a Box
pointing to the heap space. A Box
owns the space it points to, when the Box
is dropped, it frees the space too.
Just as variables own their values, structs own their fields, and tuples, arrays, and vectors own their elements.
Moves
The ownership of the Vector
is moved to t
.
If you want s
to retain its ownership of the vector, then you should use s.clone()
on assignment to t
.
More Operations That Move
Moves and Control Flow
Moves and Indexed Content
Not every kind of value owner is prepared to become uninitialized.
If you really do want to move an element out of a vector:
for
... in ... :Collection types like Vec
also generally offer methods to consume all their elements in a loop:
When we pass the vector to the loop directly, as in for ... in v
, this moves the vector out of v
, leaving v
uninitialized.
The for
loop’s internal machinery takes ownership of the vector and dissects it into its elements.
At each iteration, the loop moves another element to the variable s
. Since s now owns the string, we’re able to modify it in the loop body before printing it.
If you do want to move an element out of index, consider change the value you'd like to move to Optional
:
Copy Types: The Exception to Moves
A tuple or fixed-size array of Copy types is itself a Copy type. For example:
They can both be copied.
If all the fields of your struct are themselves Copy, then you can make the type Copy as well by placing the attribute # [derive(Copy, Clone)]
above the definition:
While C++ lets you overload assignment operators and define specialized copy and move constructors, Rust doesn’t permit this sort of customization.
Rc and Arc: Shared Ownership
Rust provides the reference-counted pointer types Rc
and Arc
.
The Rc
and Arc
types are very similar; the only difference between them is that an Arc
is safe to share between threads directly—the name Arc
is short for atomic reference count—whereas a plain Rc
uses faster non-thread-safe code to update its reference count.
Cloning an Rc<T>
value does not copy the T
; instead, it simply creates another pointer to it and increments the reference count.
Difference Between
Copy
andClone
Copy
: This trait creates a bitwise copy of an object and is implemented only by types that can be trivially duplicated. This means that the original and the copied objects occupy separate memory spaces, with no complex ownership concerns.
Clone
: This trait performs a deep copy, potentially duplicating the data that the object owns. UnlikeCopy
,Clone
can handle ownership complexities, allowing for more sophisticated duplication of objects.In the case of
Rc
, cloning it does not create a fully independent copy. Instead, the clonedRc
shares the underlying heap memory with the originalRc
, meaning both point to the same data.
You can use any of String’s usual methods directly on an Rc<String>
:
A value owned by an Rc pointer is immutable. If you need to mutate the value inside an Rc
, you have to wrap it in a RefCell
, which provides interior mutability. RefCell
allows you to borrow the value mutably at runtime, enforcing Rust’s borrowing rules dynamically rather than at compile time.
Here’s an example:
In this example, the RefCell
allows the value inside the Rc
to be mutated, even though Rc
itself doesn’t permit direct mutation.
Last updated