Passing Objects
One of the things that's "hard" about Rust when you first start learning it are the different ways you can pass an object to a function or return one, and the types associated with them.
For example, Strings come in a few different flavors, and you need to know which one to use to return them.:
#![allow(unused)] fn main() { // This works: fn return_string() -> String { let not_global = "I return ok, because I'm not global.".to_string(); not_global // Funky Rust return syntax. } // This doesn't, uncomment to see the error /* fn return_broken() -> String { let broken = "Not OK -- I'm a global literal!"; broken } */ println!("{}", return_string()); }
Mutable methods vs immutable methods
Before learning about passing objects, we need to create a basic "object" and test it, which has mutable and immutable methods.
pub struct Person { name: String, state: String, } impl Person { // See https://rust-unofficial.github.io/patterns/idioms/ctor.html pub fn new(name: String, state: String) -> Self { Self { name: name, state: state } } pub fn print(&self) { println!("{} lives in {}.", self.name, self.state); } // Note it's &mut, not mut& pub fn move_to(&mut self, state: String) { self.state = state; } } fn main() { let static_john = Person::new("John Lockwood".to_string(), "California".to_string()); static_john.print(); // Static John can't move! Next line is an error // static_john.move_to("North Carolina".to_string()); // Mutable John can let mut john = Person::new("John Lockwood".to_string(), "California".to_string()); john.print(); john.move_to("North Carolina".to_string()); john.print(); }
Passing Objects
Basically there are about four ways things can get passed around:
- Directly non-mutable
- Directly mutable
- By reference non-mutable
- By reference mutable
Passing objects directly
This MOVES the object to a new owner. If you do this, you can't use the reference any more. I.e. Can do it mutably or not.
fn pass_ownership_non_mutable(person: Person) {
person.print();
}
fn pass_ownership_mutably(mut person: Person) {
person.move_to("New York".to_string());
}
Calling:
// Pass a person not by reference
let john2 = Person::new("John".to_string(), "California".to_string());
pass_ownership_non_mutable(john2);
// Can't do -- borrowed after move: E0382:
// john2.print();
// Note we don't need to declare this as mut here
// for that it matches the function signature of pass_ownership_mutually
let john3 = Person::new("John ".to_string(), "California".to_string());
pass_ownership_mutably(john3);
// Can't do -- borrowed after move: E0382:
// john3.print();
Passing by reference
fn pass_reference_non_mutable(person: &Person) {
person.print();
}
fn pass_reference_mutably(person: &mut Person) {
person.move_to("Washington".to_string());
person.print();
}
Calling:
let mut john3 = Person::new("John ".to_string(), "California".to_string());
pass_reference_mutably(&mut john3);
// Reusing, ownership not transfered!
pass_reference_non_mutable(&john3);