The spinners crate has an enum with a large selection of possible spinners.
Here's the enum (with all values except the top and bottom 4 skipped):
pub enum Spinners { Dots, Dots2, Dots3, Dots4, ... Shark, Dqpb, Weather, Christmas, }
A new spinner is easy to create:
extern crate spinners; use spinners::{Spinner, Spinners}; use std::thread::sleep; use std::time::Duration; fn main() { let sp = Spinner::new(Spinners::Dots9, "Waiting for 3 seconds".into()); sleep(Duration::from_secs(3)); sp.stop(); }
However, I wish to select a spinner at random, and this does not work:
let spinner_enum = rng.choose(Spinners).unwrap_or(&Spinners::Dots9);
Because:
error[E0423]: expected value, found enum `Spinners` let spinner_enum = rng.choose(Spinners).unwrap_or(&Spinners::Dots9); ^^^^^^^^ not a value
How can I choose an enum value at random, and use that to display a random spinner?
No, it's not. The purpose for an Enum is to give us mapped data (fixed set of values) with limited scope. If we would to use @Value in Java enums, it would take the purpose of the enum away in the first place.
To allow us to get random value of this BaseColor enum we define a getRandomColor () method in the enum. This method use the java.util.Random to create a random value. This random value then will be used to pick a random value from the enum. Let’s see the code snippet below:
First we’ll create an enum called BaseColor which will have three valid value. These values are Red, Green and Blue. To allow us to get random value of this BaseColor enum we define a getRandomColor () method in the enum. This method use the java.util.Random to create a random value.
If you don't explicity set the values of the enums, the first element in the sequence is 0 and +1 for each going down. You can do (assuming the variable cardSuit is of type CardSuit (the enum): One more example that once again only applies to enums that haven't had their default values set.
Notice how the randomEnum () method resembles the randomDirection () method from the previous example. The difference is that the RandomEnumGenerator class has a constructor that expects an enum type from which to get the constant values. We could generate a random direction using the RandomEnumGenerator class as follows:
Like most abstractions in Rust, random value generation is powered by traits. Implementing a trait is the same for any particular type, the only difference is exactly what the methods and types of the trait are.
Implement Distribution
using your enum as the type parameter. You also need to choose a specific type of distribution; Standard
is a good default choice. Then use any of the methods to generate a value, such as rand::random
:
use rand::{ distributions::{Distribution, Standard}, Rng, }; // 0.8.0 #[derive(Debug)] enum Spinner { One, Two, Three, } impl Distribution<Spinner> for Standard { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Spinner { // match rng.gen_range(0, 3) { // rand 0.5, 0.6, 0.7 match rng.gen_range(0..=2) { // rand 0.8 0 => Spinner::One, 1 => Spinner::Two, _ => Spinner::Three, } } } fn main() { let spinner: Spinner = rand::random(); println!("{:?}", spinner); }
Implement Rand
for your enum, then use any of the methods to generate a value, such as Rng::gen
:
extern crate rand; // 0.4.2 use rand::{Rand, Rng}; #[derive(Debug)] enum Spinner { One, Two, Three, } impl Rand for Spinner { fn rand<R: Rng>(rng: &mut R) -> Self { match rng.gen_range(0, 3) { 0 => Spinner::One, 1 => Spinner::Two, _ => Spinner::Three, } } } fn main() { let mut rng = rand::thread_rng(); let spinner: Spinner = rng.gen(); println!("{:?}", spinner); }
The rand_derive
crate can remove the need for some of this boilerplate, but does not exist for Rand 0.5.
extern crate rand; #[macro_use] extern crate rand_derive; use rand::Rng; #[derive(Debug, Rand)] enum Spinner { One, Two, Three, } fn main() { let mut rng = rand::thread_rng(); let spinner: Spinner = rng.gen(); println!("{:?}", spinner); }
Since you don't control the enum, you have to copy something into your code in order to reference it. You could create an array of the enum and choose
from that:
use rand::seq::SliceRandom; // 0.8.0 mod another_crate { #[derive(Debug)] pub enum Spinner { One, Two, Three, } } fn main() { let mut rng = rand::thread_rng(); let spinners = [ another_crate::Spinner::One, another_crate::Spinner::Two, another_crate::Spinner::Three, ]; let spinner = spinners.choose(&mut rng).unwrap(); println!("{:?}", spinner); }
You could replicate the entire enum locally, implement Rand
for that, and then have a method that converts back into the other crates representation.
use rand::{ distributions::{Distribution, Standard}, Rng, }; // 0.8.0 mod another_crate { #[derive(Debug)] pub enum Spinner { One, Two, Three, } } enum Spinner { One, Two, Three, } impl From<Spinner> for another_crate::Spinner { fn from(other: Spinner) -> another_crate::Spinner { match other { Spinner::One => another_crate::Spinner::One, Spinner::Two => another_crate::Spinner::Two, Spinner::Three => another_crate::Spinner::Three, } } } impl Distribution<Spinner> for Standard { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Spinner { match rng.gen_range(0..=2) { 0 => Spinner::One, 1 => Spinner::Two, _ => Spinner::Three, } } } fn main() { let spinner = another_crate::Spinner::from(rand::random::<Spinner>()); println!("{:?}", spinner); }
You could count the number of spinners and do a match:
use rand::Rng; // 0.8.0 mod another_crate { #[derive(Debug)] pub enum Spinner { One, Two, Three, } } fn rando<R: Rng>(mut rng: R) -> another_crate::Spinner { match rng.gen_range(0..=2) { 0 => another_crate::Spinner::One, 1 => another_crate::Spinner::Two, _ => another_crate::Spinner::Three, } } fn main() { let mut rng = rand::thread_rng(); let spinner = rando(&mut rng); println!("{:?}", spinner); }
You can implement a newtype and implement the random generation for that:
use rand::{distributions::Standard, prelude::*}; // 0.8.0 mod another_crate { #[derive(Debug)] pub enum Spinner { One, Two, Three, } } struct RandoSpinner(another_crate::Spinner); impl Distribution<RandoSpinner> for Standard { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> RandoSpinner { RandoSpinner(match rng.gen_range(0..=2) { 0 => another_crate::Spinner::One, 1 => another_crate::Spinner::Two, _ => another_crate::Spinner::Three, }) } } fn main() { let RandoSpinner(spinner) = rand::random(); println!("{:?}", spinner); }
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With