Full Blog TOC

Full Blog Table Of Content with Keywords Available HERE

Monday, May 8, 2023

Rust Structures and Enums




 


Structures

Structures can hold multiple fields of multiple types.


struct Animal {
name: String,
legs: u32,
}


Instances of structures can be created, and modified:


let mut insect = Animal {
name: String::from("insect"),
legs: 12,
};

insect.legs = 6;


Builder function can be used, and we can use defaults for fields name to be as the variable names:


fn produce_6legs_animal(name: String) -> Animal {
return Animal {
name,
legs: 6,
};
}

fn main() {
let ant = produce_6legs_animal(String::from("ant"));
}


Move fields from another structure. Notice that move of values from structure means that some of the fields are no longer valid:


fn print_animal(animal: &Animal){
println!("the animal {} has {} legs", animal.name, animal.legs)
}

fn main() {
let caterpillar = Animal {
name: String::from("caterpillar"),
legs: 12,
};

print_animal(&caterpillar);

let butterfly = Animal {
legs: 6,
..caterpillar
};

print_animal(&butterfly);

// compile error - value borrowed here after partial move
print_animal(&caterpillar);
}


Unnamed struct can also be used. Notice the instance creation is using regular parenthesis:


struct Position(String, i32, i32);

fn main() {
let start = Position(String::from("start"), 0, 0);
}


Structs without any fields can also be used:


struct MyTrait;

fn main() {
let my_trait = MyTrait;
}


Moving on to Objects

Structures are used for object oriented design. Using structs and impl blocked we can create multiple constructors and methods. Notice that we can have multiple impl blocks.


struct Person {
name: String,
age: i32,
}

impl Person {
fn new_baby(name: String) -> Self {
return Person {
name,
age: 0,
};
}
fn is_very_old(&self) -> bool {
self.age > 120
}
fn is_older_than(&self, other: &Person) -> bool {
self.age > other.age
}
}


Using the objects is simple.

Again, to avoid move of ownership use pointers for structure when sending it as parameter.


fn main() {
let noah = Person {
name: String::from("Noam"),
age: 950,
};
let einstein = Person {
name: String::from("Einstein"),
age: 76,
};
let baby = Person::new_baby(String::from("Herman"));


let description = if noah.is_very_old() { "very old" } else { "young" };

println!("the person {:?} is {}", noah.name, description);
if noah.is_older_than(&einstein) {
println!("Noah is older than Einstein")
}
}


Debugging 

By adding #[derive(Debug)] attribute to a structure we can print it in a single line using {:?}, and in multiple lines using {:#?}. In addition we can use the dbg! macro to print code position and variable information.

let baby = Person::new_baby(String::from("Herman"));
println!("single line print {:?}", baby);
println!("multiple lines print {:#?}", baby);
dbg!(&baby);

The output is:

single line print Person { name: "Herman", age: 0 }

multiple lines print Person {
name: "Herman",
age: 0,
}

[src/main.rs:26] &baby = Person {
name: "Herman",
age: 0,
}



Enums

Enums can be just a list, or even hold properties similarly to structs.
In addition, enums can be used in match arms.

use crate::Furniture::{Closet, Table};

#[derive(Debug)]
enum Furniture {
Chair,
Table,
Closet { doors: u32 },
}

impl Furniture {
fn open(&self) {
match self {
Closet { doors } => {
println!("open {doors} doors");
}
_ => (
println!("no need to open")
)
}
}
}

fn main() {
let chair = Furniture::Chair;
let closet = Closet { doors: 2 };
println!("{:?}", chair);
println!("{:?}", closet);

chair.open();
closet.open();
}

Option


A special enum is Option, which can hold a value, and can also contain None.
Notice that match expression must be exhaustive, that is - hold all possible values: Some and None.


fn square(i: Option<i32>) -> Option<i32> {
return match i {
Some(x) => Some(x * x),
None => None,
};
}

fn main() {
let two = Some(2);
let none = None;

// prints Some(4)
println!("{:?}", square(two));
// prints None
println!("{:?}", square(none));
}

We can also check value of an option using "if let" statement.

if let Some(i) = two {
println!("the actual value of the option is {}", i)
}



No comments:

Post a Comment