How do you access enum values in Rust? - rust

struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
I want to print out circle's second property, which is 10.0 here.
I tried my_shape.last and my_shape.second, but neither worked.
What should I do in order to print out 10.0 in this case?

As you are only interested in matching one of the variants, you can use an if let expression instead of a match:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
if let Shape::Circle(_, radius) = my_shape {
println!("value: {}", radius);
}
}
This means "if my_shape can be destructured into a Circle, do nothing with the first index, but bind the value of the second index to radius".

You can use pattern matching:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
match my_shape {
Shape::Circle(_, value) => println!("value: {}", value),
_ => println!("Something else"),
}
}
Example output:
value: 10

Here is another way to do it:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
}
fn main() {
let Shape::Circle(_, radius) = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
println!("value: {}", radius);
}
This only works if the pattern is irrefutable, such as when the enum type you're matching on only has one variant. To make this work, I had to remove the unused Rectangle variant.
In cases where you have more than one variant, you'll probably want the full match expression anyway, since you're presumably handling more than just one kind of shape.

From The Rust Programming Language:
Another useful feature of match arms is that they can bind to parts of the values that match the pattern. This is how we can extract values out of enum variants.
[...]
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
If you'd like to be able to write functions that are capable of working on multiple types with different representations, have a look at traits.

For a simple retrieval of value, you can use "if let"
let mut var: f64 = 0.0;
if let Shape::Circle(_, float1) = my_shape {
var = float1;
}
println!("value is {}", var);

let r = match my_shape { Shape::Circle(_, r) => r, _ => 0f64 };
or
let r = if let Shape::Circle(_, r) = my_shape { r } else { 0f64 };

Related

How do I remove code duplication to make a generic function to handle all kind of entities in Rust?

I have asteroids; players and lasers are entities. Instead of the following code, is it possible to make one function that takes generic as argument and produce the same output. I understand ECS is an ideal way of handling this. But am curious if this would be possible.
// check collision between asteroid and players
pub fn check_collission_between_asteroid_and_players(asteroids: &mut Vec<Asteroid>, players: &mut Vec<Player>) {
for player in players.iter_mut() {
for asteroid in asteroids.iter_mut() {
if player.entity.position.distance(asteroid.entity.position) < asteroid.radius + player.radius {
player.kill();
asteroid.kill();
}
}
}
}
// check collission between player and players
pub fn check_collission_between_player_and_players(players: &mut Vec<Player>) {
for player in players.iter_mut() {
for other_player in players.iter_mut() {
if player.entity.position.distance(other_player.entity.position) < player.radius + other_player.radius && player != other_player {
player.kill();
other_player.kill();
}
}
}
}
// check collission between lasers and players
pub fn check_collission_between_lasers_and_players(lasers: &mut Vec<Laser>, players: &mut Vec<Player>) {
for player in players.iter_mut() {
for laser in lasers.iter_mut() {
if player.entity.position.distance(laser.entity.position) < player.radius + laser.radius {
player.kill();
laser.kill();
}
}
}
}
// check collission between lasers and asteroids
pub fn check_collission_between_lasers_and_asteroids(lasers: &mut Vec<Laser>, asteroids: &mut Vec<Asteroid>) {
for laser in lasers.iter_mut() {
for asteroid in asteroids.iter_mut() {
if laser.entity.position.distance(asteroid.entity.position) < laser.radius + asteroid.radius {
laser.kill();
asteroid.kill();
}
}
}
}
You can implement a Trait that can collide and kill, and use a generic function:
#[derive(Debug, Clone, Copy)]
struct Position {
x: f64,
y: f64,
}
struct Player {
position: Position,
}
struct Asteroid {
position: Position,
}
trait Collidable {
fn position(&self) -> Position;
fn kill(&self);
}
impl Collidable for Player {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Player dying at coordinate {:?}", self.position);
}
}
impl Collidable for Asteroid {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Asteroid dying at coordinate {:?}", self.position);
}
}
fn check_collisions<T: Collidable, U: Collidable>(t_vec: &mut[T], u_vec: &mut[U], max_dist: f64) {
for t in t_vec.iter_mut() { // Note you're now comparing the same objects twice in some cases
for u in u_vec.iter_mut() {
let t_pos = t.position();
let u_pos = u.position();
// Some calc to determine distance:
let distance = ((t_pos.x - u_pos.x).abs().powf(2.) + (t_pos.y - u_pos.y).abs().powf(2.)).powf(0.5);
if distance < max_dist {
println!("Collision!");
u.kill();
t.kill();
}
}
}
}
let mut players = vec![
Player { position: Position {x: 1.0, y: 1.0}},
Player { position: Position {x: 3.0, y: 3.0}}];
let mut asteroids = vec![
Asteroid { position: Position {x: 2.0, y: 2.0}},
Asteroid { position: Position {x: 10.0, y: 10.0}}];
check_collisions(&mut players, &mut asteroids, 5.);
Based on #Rob's answer, here is a version that uses Trait Objects so that you have one method that will check all collisions between objects. The code is mostly the same except for the check_all method and the way you have to construct the vector:
#[derive(Debug, Clone, Copy)]
struct Position {
x: f64,
y: f64,
}
struct Player {
position: Position,
}
struct Asteroid {
position: Position,
}
trait Collidable {
fn position(&self) -> Position;
fn kill(&self);
}
impl Collidable for Player {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Player dying at coordinate {:?}", self.position);
}
}
impl Collidable for Asteroid {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Asteroid dying at coordinate {:?}", self.position);
}
}
fn check_all(t_vec: &mut[Box<dyn Collidable>], max_dist: f64) {
for i in 0..t_vec.len() {
for j in i+1..t_vec.len() {
let i_pos = t_vec[i].position();
let j_pos = t_vec[j].position();
let distance = ((i_pos.x - j_pos.x).abs().powf(2.) + (i_pos.y - j_pos.y).abs().powf(2.)).powf(0.5);
if distance < max_dist {
println!("Collision!");
t_vec[i].kill();
t_vec[j].kill();
}
}
}
}
fn main() {
let mut objects: Vec<Box<dyn Collidable>> = vec![
Box::new(Player { position: Position {x: 1.0, y: 1.0}}),
Box::new(Player { position: Position {x: 3.0, y: 3.0}}),
Box::new(Asteroid { position: Position {x: 2.0, y: 2.0}}),
Box::new(Asteroid { position: Position {x: 10.0, y: 10.0}})];
check_all(&mut objects, 5.);
}
I'm using explicit indices i and j instead of grabbing the objects to avoid the problem that you can't have two mutable references to vector elements at the same time.
Btw, in the current version of the code we don't actually need the vector elements to be mutable, but probably in real code where the kill method does something to the object, we'd need to make it fn kill(&mut self) instead.

How to extract value inside enum? [duplicate]

struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
I want to print out circle's second property, which is 10.0 here.
I tried my_shape.last and my_shape.second, but neither worked.
What should I do in order to print out 10.0 in this case?
As you are only interested in matching one of the variants, you can use an if let expression instead of a match:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
if let Shape::Circle(_, radius) = my_shape {
println!("value: {}", radius);
}
}
This means "if my_shape can be destructured into a Circle, do nothing with the first index, but bind the value of the second index to radius".
You can use pattern matching:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
match my_shape {
Shape::Circle(_, value) => println!("value: {}", value),
_ => println!("Something else"),
}
}
Example output:
value: 10
Here is another way to do it:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
}
fn main() {
let Shape::Circle(_, radius) = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
println!("value: {}", radius);
}
This only works if the pattern is irrefutable, such as when the enum type you're matching on only has one variant. To make this work, I had to remove the unused Rectangle variant.
In cases where you have more than one variant, you'll probably want the full match expression anyway, since you're presumably handling more than just one kind of shape.
From The Rust Programming Language:
Another useful feature of match arms is that they can bind to parts of the values that match the pattern. This is how we can extract values out of enum variants.
[...]
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
If you'd like to be able to write functions that are capable of working on multiple types with different representations, have a look at traits.
For a simple retrieval of value, you can use "if let"
let mut var: f64 = 0.0;
if let Shape::Circle(_, float1) = my_shape {
var = float1;
}
println!("value is {}", var);
let r = match my_shape { Shape::Circle(_, r) => r, _ => 0f64 };
or
let r = if let Shape::Circle(_, r) = my_shape { r } else { 0f64 };

Access values of individual items in an enum [duplicate]

struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
I want to print out circle's second property, which is 10.0 here.
I tried my_shape.last and my_shape.second, but neither worked.
What should I do in order to print out 10.0 in this case?
As you are only interested in matching one of the variants, you can use an if let expression instead of a match:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
if let Shape::Circle(_, radius) = my_shape {
println!("value: {}", radius);
}
}
This means "if my_shape can be destructured into a Circle, do nothing with the first index, but bind the value of the second index to radius".
You can use pattern matching:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
match my_shape {
Shape::Circle(_, value) => println!("value: {}", value),
_ => println!("Something else"),
}
}
Example output:
value: 10
Here is another way to do it:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
}
fn main() {
let Shape::Circle(_, radius) = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
println!("value: {}", radius);
}
This only works if the pattern is irrefutable, such as when the enum type you're matching on only has one variant. To make this work, I had to remove the unused Rectangle variant.
In cases where you have more than one variant, you'll probably want the full match expression anyway, since you're presumably handling more than just one kind of shape.
From The Rust Programming Language:
Another useful feature of match arms is that they can bind to parts of the values that match the pattern. This is how we can extract values out of enum variants.
[...]
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
If you'd like to be able to write functions that are capable of working on multiple types with different representations, have a look at traits.
For a simple retrieval of value, you can use "if let"
let mut var: f64 = 0.0;
if let Shape::Circle(_, float1) = my_shape {
var = float1;
}
println!("value is {}", var);
let r = match my_shape { Shape::Circle(_, r) => r, _ => 0f64 };
or
let r = if let Shape::Circle(_, r) = my_shape { r } else { 0f64 };

How do you access structs inside enums? [duplicate]

struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
I want to print out circle's second property, which is 10.0 here.
I tried my_shape.last and my_shape.second, but neither worked.
What should I do in order to print out 10.0 in this case?
As you are only interested in matching one of the variants, you can use an if let expression instead of a match:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
if let Shape::Circle(_, radius) = my_shape {
println!("value: {}", radius);
}
}
This means "if my_shape can be destructured into a Circle, do nothing with the first index, but bind the value of the second index to radius".
You can use pattern matching:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
Rectangle(Point, Point),
}
fn main() {
let my_shape = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
match my_shape {
Shape::Circle(_, value) => println!("value: {}", value),
_ => println!("Something else"),
}
}
Example output:
value: 10
Here is another way to do it:
struct Point {
x: f64,
y: f64,
}
enum Shape {
Circle(Point, f64),
}
fn main() {
let Shape::Circle(_, radius) = Shape::Circle(Point { x: 0.0, y: 0.0 }, 10.0);
println!("value: {}", radius);
}
This only works if the pattern is irrefutable, such as when the enum type you're matching on only has one variant. To make this work, I had to remove the unused Rectangle variant.
In cases where you have more than one variant, you'll probably want the full match expression anyway, since you're presumably handling more than just one kind of shape.
From The Rust Programming Language:
Another useful feature of match arms is that they can bind to parts of the values that match the pattern. This is how we can extract values out of enum variants.
[...]
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
If you'd like to be able to write functions that are capable of working on multiple types with different representations, have a look at traits.
For a simple retrieval of value, you can use "if let"
let mut var: f64 = 0.0;
if let Shape::Circle(_, float1) = my_shape {
var = float1;
}
println!("value is {}", var);
let r = match my_shape { Shape::Circle(_, r) => r, _ => 0f64 };
or
let r = if let Shape::Circle(_, r) = my_shape { r } else { 0f64 };

Do Rust builder patterns have to use redundant struct code?

I was looking at the Method syntax section of the Rust documentation and came across an example of the builder pattern. The CircleBuilder struct in the example below is an exact duplicate of the Circle struct. It seems like this redundant code violates the usual norms of programming.
I understand why the example created a new struct, because the creator did not want to implement the builder methods against the original Circle struct. That is fine, but is there a way to rewrite this example so that there is no redundancy--yet still keeping the nice builder interface in the main() function intact?
I tried to create an empty struct or a struct with just one throwaway element, but that did not work.
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
struct CircleBuilder {
x: f64,
y: f64,
radius: f64,
}
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
Do Rust builder patterns have to use redundant struct code?
No. But sometimes they might. For example, consider if we wanted to have special logic (or even just complicated logic) around our constructor:
/// Width must always be greater than height!
struct HorizontalEllipse {
width: f64,
height: f64,
}
impl HorizontalEllipse {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.width / 2.0) * (self.height / 2.0)
}
}
struct HorizontalEllipseBuilder {
width: f64,
height: f64,
}
impl HorizontalEllipseBuilder {
fn new() -> HorizontalEllipseBuilder {
HorizontalEllipseBuilder {
width: 0.0,
height: 0.0,
}
}
fn width(&mut self, width: f64) -> &mut HorizontalEllipseBuilder {
self.width = width;
self
}
fn height(&mut self, height: f64) -> &mut HorizontalEllipseBuilder {
self.height = height;
self
}
fn finalize(&self) -> Result<HorizontalEllipse, String> {
let HorizontalEllipseBuilder { height, width } = *self;
if height >= width {
Err("This is not horizontal".into())
} else {
Ok(HorizontalEllipse { width, height })
}
}
}
fn main() {
let c = HorizontalEllipseBuilder::new()
.width(1.0)
.height(2.0)
.finalize()
.expect("not a valid ellipse");
println!("area: {}", c.area());
println!("width: {}", c.width);
println!("height: {}", c.height);
}
Now a HorizontalEllipse knows that it is always true that width > height. We've moved that check from many potential places (each method) to one, the constructor. We then moved the constructor to a new type because it was complicated (not really, but truly complicated examples are usually... complicated).
Many builders I've seen also have "enhanced" types of the real object:
#[derive(Debug)]
struct Person {
name: String,
}
#[derive(Debug, Default)]
struct PersonBuilder {
name: Option<String>,
}
impl PersonBuilder {
fn name(self, name: &str) -> Self {
PersonBuilder { name: Some(name.into()), ..self }
}
fn build(self) -> Person {
Person {
name: self.name.unwrap_or_else(|| "Stefani Joanne Angelina Germanotta".into()),
}
}
}
fn main() {
let person = PersonBuilder::default().build();
println!("{:?}", person);
let person = PersonBuilder::default().name("krishnab").build();
println!("{:?}", person);
}
You don't see that in the book's example because it's trying to be simpler and not involve ownership concerns.
This seems like the sort of thing a macro might be able to do. A quick search found the derive_builder and builder_macro crates which seem to implement this functionality.

Resources