Rust Practice

This contains a list of practice problems to learn rust syntax generated by Gemini.

Rust Syntax Drills

Drill 1: The “Contact Manager” (Structs & Impl)

Goal: Practice defining data structures and methods (The Rust “Class” equivalent).

  • Define a struct User with fields: username (String), email (String), - [ ] and login_count (u64).
  • Create an impl block for User.
  • Implement fn new(username: &str, email: &str) -> Self.
  • Implement fn display(&self) to print user details.
  • Implement fn increment_login(&mut self) to increase the count.
  • In main, instantiate a mutable user and call all methods.

Drill 2: The “Atmospheric Sensor” (Enums & Match)

Goal: Practice Rust’s specific Enum syntax and pattern matching.

  • Define an enum Temperature with variants: Celsius(f64) and Fahrenheit(f64).
  • Write a function to_celsius(temp: Temperature) -> f64.
  • Inside the function, use match to handle both variants.
  • Formula for Fahrenheit to Celsius: (f - 32.0) * 5.0 / 9.0.
  • In main, create one of each variant and print the converted values.

Drill 3: The “Shopping List” (Vectors & Ownership)

Goal: Practice the difference between borrowing (&) and moving ownership.

  • In main, create a let mut list = Vec::new();.
  • Add three String items to the list.
  • Create fn print_list(val: &Vec<String>) that uses a for loop to print items.
  • Create fn consume_list(val: Vec<String>) that prints the length and “drops” the list.
  • In main, call print_list (borrow), then consume_list (move).
  • Try to call print_list one more time at the end to see the compiler error.

Drill 4: The “Safe Divider” (Result & Error Handling)

Goal: Practice the Result type and the match vs if let syntax.

  • Write a function divide(a: f64, b: f64) -> Result<f64, String>.
  • Return Err("Cannot divide by zero".to_string()) if b == 0.0.
  • In main, call the function with a valid divisor and use match to print the result.
  • Call the function with 0.0 and use if let Err(e) = ... to print only the error message.
  • Practice using the “implicit return” (no semicolon) for the function result.

Rust Intermediate Drills

Drill 5: Random Indexer (External Crates)

  • Setup rand crate in Cargo.toml.
  • Create a Vec of strings.
  • Use gen_range(0..vec.len()) to pick a random item.
  • Practice: Ensure the program doesn’t panic if the Vec is empty.

Drill 6: The Cipher Trait (Traits)

  • Define trait Cipher { fn encrypt(&self, data: &str) -> String; }.
  • Implement Cipher for two different “mock” encryption structs.
  • Create a function that accepts &dyn Cipher or &impl Cipher.
  • Observe how Rust handles “Interface” behavior.

Drill 7: Generic Vault (Generics)

  • Define struct Vault<T>.
  • Implement new and get methods for the generic type.
  • Instantiate it with a String and then with a u32.

Drill 8: OS Entropy (Crypto-Ready)

  • Import rand::rngs::OsRng and rand::RngCore.
  • Fill a byte buffer mut key = [0u8; 16] with random data using OsRng.fill_bytes().
  • Print the buffer as a Hex string.

Drill 9: The “Plugin” System (Dynamic Dispatch)

Practice using dyn and Box to store different types in a single collection.

  • Define a trait Plugin with two methods:
    • fn name(&self) -> &str;
    • fn run(&self);
  • Create a struct AudioPlugin and implement Plugin.
    • name should return “Audio”. run should print “Playing sound…“.
  • Create a struct VideoPlugin and implement Plugin.
    • name should return “Video”. run should print “Showing frames…“.
  • In main, create a Vec<Box<dyn Plugin>>.
  • Add one AudioPlugin and one VideoPlugin to the vector.
    • Hint: Use Box::new(AudioPlugin).
  • Loop through the vector and call .run() on each plugin.

Bonus Challenge:

  • Try creating a function execute_plugin(p: &dyn Plugin) and pass an element from your vector to it. This teaches you how to move from a Box (ownership) to a &dyn (borrow).