s, t and u actually points to the same PyListObject.
usingnamespacestd;vector<string> s ={"udon","ramen","soba"};vector<string> t = s;vector<string> u = s;
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.
fnprint_padovan(){letmutpadovan=vec![1,1,1];// allocated here foriin3..10{letnext=padovan[i-3]+padovan[i-2];padovan.push(next);}println!("P(1..10) = {:?}",padovan);}// dropped here
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 and Clone
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. Unlike Copy, 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 cloned Rc shares the underlying heap memory with the original Rc, 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.
{
let point = Box::new((0.625, 0.5)); // point allocated here
let label = format!("{:?}", point); // label allocated here
assert_eq!(label, "(0.625, 0.5)");
} // both dropped here
struct Person { name: String, birth: i32 }
let mut composers = Vec::new();
composers.push(Person { name: "Palestrina".to_string(), birth: 1525 });
composers.push(Person { name: "Dowland".to_string(), birth: 1563 });
composers.push(Person { name: "Lully".to_string(), birth: 1632 });
for composer in &composers {
println!("{}, born {}", composer.name, composer.birth);
}
let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
let t = s;
let mut s = "Govinda".to_string();
s = "Siddhartha".to_string(); // value "Govinda" dropped here
let mut s = "Govinda".to_string();
let t = s;
s = "Siddhartha".to_string(); // nothing is dropped here
let x = vec![10, 20, 30];
if c {
f(x); // ... ok to move from x here
} else {
g(x); // ... and ok to also move from x here
}
h(x); // bad: x is uninitialized here if either path uses it
let x = vec![10, 20, 30];
while f() {
g(x); // bad: x would be moved in first iteration,
// uninitialized in second
}
// Build a vector of the strings "101", "102", ... "105"
let mut v = Vec::new();
for i in 101 .. 106 {
v.push(i.to_string());
}
// Pull out random elements from the vector.
let third = v[2]; // error: Cannot move out of index of Vec
let fifth = v[4]; // here too
// Build a vector of the strings "101", "102", ... "105"
let mut v = Vec::new();
for i in 101 .. 106 {
v.push(i.to_string());
}
// 1. Pop a value off the end of the vector:
let fifth = v.pop().expect("vector empty!");
assert_eq!(fifth, "105");
// 2. Move a value out of a given index in the vector,
// and move the last element into its spot:
let second = v.swap_remove(1);
assert_eq!(second, "102");
// 3. Swap in another value for the one we're taking out:
let third = std::mem::replace(&mut v[2], "substitute".to_string());
assert_eq!(third, "103");
let v = vec!["liberté".to_string(), "égalité".to_string(),
"fraternité".to_string()];
for mut s in v {
s.push('!');
println!("{}", s);
}
struct Person { name: Option<String>, birth: i32 }
let mut composers = Vec::new();
composers.push(Person { name: Some("Palestrina".to_string()),
birth: 1525 });
let first_name = std::mem::replace(&mut composers[0].name, None);
// Or more conveniently
let first_name = composers[0].name.take();
let nums_1: [i32; 5] = [1, 2, 3, 4, 5];
let nums_2 = (1, 2, 3, 4, 5);
use std::rc::Rc;
// Rust can infer all these types; written out for clarity
let s: Rc<String> = Rc::new("shirataki".to_string());
let t: Rc<String> = s.clone();
let u: Rc<String> = s.clone();
assert!(s.contains("shira"));
assert_eq!(t.find("taki"), Some(5));
println!("{} are quite chewy, almost bouncy, but lack flavor", u);
use std::rc::Rc;
use std::cell::RefCell;
let value = Rc::new(RefCell::new(5));
*value.borrow_mut() += 1;