Compare commits
6 Commits
595ac0e75b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
47ed183cfe
|
|||
|
76cb232b1e
|
|||
|
621fb6bb59
|
|||
|
d745026c1a
|
|||
|
b25fe11bc7
|
|||
|
89fd568b75
|
@@ -41,7 +41,11 @@ fn main() {
|
||||
// Hint: .to_uppercase() is a method on `str` which returns a String
|
||||
|
||||
let words = vec!["autobot", "beach", "car", "decepticon", "energon", "frothy"];
|
||||
let transformed = words.into_iter().filter(|w| !w.contains("h")).map(|w| w.to_uppercase()).collect::<Vec<String>>();
|
||||
let transformed = words
|
||||
.into_iter()
|
||||
.filter(|w| !w.contains("h"))
|
||||
.map(|w| w.to_uppercase())
|
||||
.collect::<Vec<String>>();
|
||||
println!("Transformed: {:?}", transformed);
|
||||
|
||||
// Challenge:
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
// - Document the "orangeness" field, explaining that it is a number from 8 to 27
|
||||
|
||||
/// Big orange thing
|
||||
///
|
||||
///
|
||||
/// # Recipes
|
||||
///
|
||||
///
|
||||
/// Recipes will be coming soon.
|
||||
pub struct Pumpkin {
|
||||
/// `roundness` is a percentage that describes how round the pumpkin is.
|
||||
|
||||
@@ -14,7 +14,18 @@
|
||||
// Once you have completed defining the error type correctly, you should be able to run
|
||||
// `cargo build --lib` without any build errors or warnings. Then go to main.rs and continue with #2
|
||||
|
||||
// pub enum DolphinError...
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum DolphinError {
|
||||
#[error("The dolphin is hungry")]
|
||||
Hungry,
|
||||
#[error("The dolphin is too young")]
|
||||
TooYoung,
|
||||
#[error("The dolphin's name is too long and annoying to say")]
|
||||
LongName,
|
||||
}
|
||||
|
||||
pub struct Dolphin {
|
||||
pub name: String,
|
||||
|
||||
@@ -3,30 +3,32 @@
|
||||
use aquarium::Dolphin;
|
||||
// Silence some warnings so they don't distract from the exercise.
|
||||
#[allow(clippy::vec_init_then_push)]
|
||||
|
||||
// (You already did #1 in lib.rs, right?)
|
||||
//
|
||||
// 2a. Uncomment and finish the play_time function below
|
||||
// - Bring anyhow::Result into scope with a `use` statement
|
||||
// - Have the play_time function return a `Result<Vec<String>>`. The vector of Strings will
|
||||
// represent successful outcomes of various dolphin tricks.
|
||||
use anyhow::Result;
|
||||
|
||||
// fn play_time(dolphin: &Dolphin) -> ... {
|
||||
// let mut responses = vec![];
|
||||
// // 2b. Call the .say_your_name() method on `dolphin`, use `?` to unwrap the value, and push
|
||||
// // the value onto the `responses` vector.
|
||||
// //
|
||||
// // let response = ... // this can be done with an intermediate variable...
|
||||
// // responses.push( ... ) // ...or all on one line. Either way is fine!
|
||||
// //
|
||||
// // 2c. Do the same thing as #2b for the .flip() method
|
||||
// //
|
||||
// // 2d. Do the same thing as #2b for the .shake_hands() method
|
||||
//
|
||||
// Ok(responses)
|
||||
// }
|
||||
fn play_time(dolphin: &Dolphin) -> Result<Vec<String>> {
|
||||
let mut responses = vec![];
|
||||
// 2b. Call the .say_your_name() method on `dolphin`, use `?` to unwrap the value, and push
|
||||
// the value onto the `responses` vector.
|
||||
//
|
||||
let response = dolphin.say_your_name()?; // this can be done with an intermediate variable...
|
||||
responses.push(response); // ...or all on one line. Either way is fine!
|
||||
//
|
||||
// 2c. Do the same thing as #2b for the .flip() method
|
||||
responses.push(dolphin.flip()?);
|
||||
//
|
||||
// 2d. Do the same thing as #2b for the .shake_hands() method
|
||||
responses.push(dolphin.shake_hands()?);
|
||||
|
||||
fn main() {
|
||||
Ok(responses)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let dolphins = vec![
|
||||
Dolphin {
|
||||
name: "Augustinius".into(),
|
||||
@@ -52,19 +54,28 @@ fn main() {
|
||||
for dolphin in &dolphins {
|
||||
// Challenge: Change main() so that it returns a Result, and instead of handling the error
|
||||
// that play_time returns, use the try (?) operator to only handle the success condition.
|
||||
//
|
||||
//
|
||||
// If done correctly, the output of the program will become much shorter. Since play_time
|
||||
// returns an Err variant the first time it is called, the try operator will return it from
|
||||
// main(), which will end the program at the first error. anyhow's Result will take care of
|
||||
// formatting the error output for us.
|
||||
|
||||
match play_time(dolphin) {
|
||||
Ok(responses) => {
|
||||
println!("{} did a FABULOUS PERFORMANCE!", dolphin.name);
|
||||
println!("\n{} did a FABULOUS PERFORMANCE!", dolphin.name);
|
||||
for response in responses {
|
||||
println!(" {}", response);
|
||||
}
|
||||
}
|
||||
Err(e) => println!("{} can't perform today: {}", dolphin.name, e.to_string()),
|
||||
}
|
||||
|
||||
// let responses = play_time(dolphin)?;
|
||||
// println!("\n{} did a FABULOUS PERFORMANCE!", dolphin.name);
|
||||
// for response in responses {
|
||||
// println!(" {}", response);
|
||||
// }
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,10 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# I'm glad you came to add the `log` dependency! I got it all ready for you, just uncomment:
|
||||
#
|
||||
# log = "0.4"
|
||||
|
||||
# And here's the env_logger dependency that you'll need in main.rs
|
||||
#
|
||||
# env_logger = "0.9"
|
||||
log = "0.4" # I'm glad you came to add the `log` dependency! I got it all ready for you, just uncomment:
|
||||
env_logger = "0.9" # And here's the env_logger dependency that you'll need in main.rs
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
//
|
||||
// Hint: You need to update Cargo.toml to add the `log` dependency, first.
|
||||
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Frog {
|
||||
energy: u8,
|
||||
@@ -15,19 +17,23 @@ pub struct Frog {
|
||||
impl Frog {
|
||||
pub fn new() -> Self {
|
||||
// 2. Use debug!() to log "A new Frog has been created"
|
||||
debug!(target: "Frog::new", "A new Frog has been created");
|
||||
Default::default()
|
||||
}
|
||||
pub fn hop(&mut self) {
|
||||
self.energy -= 1;
|
||||
// 3. Use info!() to log that a Frog hopped, and how much energy is left
|
||||
info!(target: "Frog::hop", "A frog hopped! It has {} energy left", self.energy);
|
||||
if self.energy == 0 {
|
||||
// 4. Use warn!() to warn that the frog will go to sleep since he ran out of energy
|
||||
warn!(target: "Frog::hop", "The frog will go to sleep since he ran out of energy");
|
||||
self.sleep();
|
||||
}
|
||||
}
|
||||
pub fn sleep(&mut self) {
|
||||
if self.sleeping {
|
||||
// 5. Use error!() to log a (non-fatal) error stating that the Frog is already asleep
|
||||
error!(target: "Frog::sleep", "The frog is already asleep");
|
||||
} else {
|
||||
self.sleeping = true;
|
||||
}
|
||||
@@ -37,9 +43,12 @@ impl Frog {
|
||||
impl Default for Frog {
|
||||
fn default() -> Self {
|
||||
// 6. Use trace!() to log that a default value was generated, with the debug representation
|
||||
Frog {
|
||||
let frog = Frog {
|
||||
energy: 5,
|
||||
sleeping: false,
|
||||
}
|
||||
};
|
||||
|
||||
trace!(target: "Frog::Default", "A default Frog value was generated: {:?}", frog);
|
||||
frog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use frogger::Frog;
|
||||
|
||||
fn main() {
|
||||
// 8. Initialize env_logger using the init() function at the top level of the library
|
||||
env_logger::init();
|
||||
|
||||
// 9. Run this program with `cargo run` and take a look at the default output.
|
||||
// - Now run it again with an explicit log level, like `RUST_LOG=info cargo run`
|
||||
|
||||
@@ -9,15 +9,15 @@ edition = "2021"
|
||||
# Challenge Help 1: If you choose to take on the challenge, you'll need to add `criterion` as a
|
||||
# development dependency. Here is one way to do it:
|
||||
|
||||
# [dev-dependencies]
|
||||
# criterion = { version = "0.3", features = ["html_reports"] }
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
|
||||
# Challenge Help 2: Each benchmark needs a `[[bench]]` section with a name and disabling the harness.
|
||||
# A name "somename" will correspond with a file "benches/somename.rs"
|
||||
|
||||
# [[bench]]
|
||||
# name = "somename"
|
||||
# harness = false
|
||||
[[bench]]
|
||||
name = "somename"
|
||||
harness = false
|
||||
|
||||
# Challenge Help 3: The Criterion documentation has a great tutorial for how to actually write your
|
||||
# benchmark. Don't skip the part about `black_box()`!
|
||||
|
||||
11
exercise/testing/benches/somename.rs
Normal file
11
exercise/testing/benches/somename.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use testing::sploosh;
|
||||
|
||||
pub fn sploosh_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("sploosh", |b| {
|
||||
b.iter(|| sploosh(black_box(8), black_box(9), black_box(10)))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, sploosh_benchmark);
|
||||
criterion_main!(benches);
|
||||
@@ -3,6 +3,7 @@ pub fn sploosh(x: i32, y: i32, z: i32) -> i32 {
|
||||
(x, _, _) if x < 0 => 99,
|
||||
(1, 2, 3) => 4,
|
||||
(5, 6, 7) => 3,
|
||||
(8, 9, 10) => 7,
|
||||
(x, y, z) => x + y - z,
|
||||
}
|
||||
}
|
||||
@@ -13,9 +14,11 @@ pub fn splish(a: i32, b: i32) -> i32 {
|
||||
|
||||
// 1. Use the `cfg` attribute to mark the `test` module below as a test module
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// 2. Bring all the library items into scope with a `use` statement
|
||||
// Hint: It's okay to use `*` here.
|
||||
use super::*;
|
||||
|
||||
// 3. Write a test function that verifies the following condition using the `assert_eq!` or
|
||||
// `assert_ne!` macros
|
||||
@@ -26,10 +29,24 @@ mod test {
|
||||
// `cargo test` should run your tests and pass
|
||||
// Hint: Don't forget the `#[test]` attribute for your test function!
|
||||
|
||||
#[test]
|
||||
fn test_sploosh() {
|
||||
assert_eq!(sploosh(1, 2, 3), 4);
|
||||
assert_ne!(sploosh(5, 6, 7), 4);
|
||||
assert_eq!(sploosh(-1, 2, 3), 99);
|
||||
}
|
||||
|
||||
// 4. Write a test function that verifies the following conditions using the `assert!` macro
|
||||
// - splish(100, 10) is negative
|
||||
// - splish(40, 20) is positive
|
||||
// - splish(9, 3) is 0
|
||||
|
||||
#[test]
|
||||
fn test_splish() {
|
||||
assert!(splish(100, 10) < 0);
|
||||
assert!(splish(40, 20) > 0);
|
||||
assert!(splish(9, 3) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Create a `tests/` directory and an integration test file `tests/more_tests.rs`
|
||||
|
||||
6
exercise/testing/tests/more_tests.rs
Normal file
6
exercise/testing/tests/more_tests.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use testing::{splish, sploosh};
|
||||
|
||||
#[test]
|
||||
pub fn test_sploosh_splish() {
|
||||
assert_eq!(sploosh(splish(-1, 0), splish(1, 1), splish(3, 2)), 4);
|
||||
}
|
||||
@@ -22,8 +22,8 @@ fn main() {
|
||||
// join handle in a variable called `handle`. Once you've done this you should be able to run
|
||||
// the code and see the output from the child thread's expensive sum in the middle of the main
|
||||
// thread's processing of letters.
|
||||
//
|
||||
//let handle = ...
|
||||
|
||||
let handle = thread::spawn(|| expensive_sum(my_vector));
|
||||
|
||||
// While the child thread is running, the main thread will also do some work
|
||||
for letter in vec!["a", "b", "c", "d", "e", "f"] {
|
||||
@@ -37,63 +37,90 @@ fn main() {
|
||||
// to a variable named `result`
|
||||
// - Get the i32 out of `result` and store it in a `sum` variable.
|
||||
|
||||
// let result =
|
||||
// let sum =
|
||||
// println!("The child thread's expensive sum is {}", sum);
|
||||
let result = handle.join();
|
||||
let sum = result.unwrap();
|
||||
println!("The child thread's expensive sum is {}", sum);
|
||||
|
||||
// 3. Time for some fun with channels!
|
||||
// - Uncomment the block comment below (Find and remove the `/*` and `*/`).
|
||||
// - Create variables `tx` and `rx` and assign them to the sending and receiving ends of an
|
||||
// unbounded channel. Hint: An unbounded channel can be created with `channel::unbounded()`
|
||||
|
||||
/*
|
||||
// let ...
|
||||
let (tx, rx) = channel::unbounded();
|
||||
|
||||
// Cloning a channel makes another variable connected to that end of the channel so that you can
|
||||
// send it to another thread. We want another variable that can be used for sending...
|
||||
let tx2 = tx.clone();
|
||||
// Cloning a channel makes another variable connected to that end of the channel so that you can
|
||||
// send it to another thread. We want another variable that can be used for sending...
|
||||
let tx2 = tx.clone();
|
||||
|
||||
// 4. Examine the flow of execution of "Thread A" and "Thread B" below. Do you see how their
|
||||
// output will mix with each other?
|
||||
// - Run this code. Notice the order of output from Thread A and Thread B.
|
||||
// - Increase the value passed to the first `sleep_ms()` call in Thread A so that both the
|
||||
// Thread B outputs occur *before* Thread A outputs anything.
|
||||
// - Run the code again and make sure the output comes in a different order.
|
||||
// 4. Examine the flow of execution of "Thread A" and "Thread B" below. Do you see how their
|
||||
// output will mix with each other?
|
||||
// - Run this code. Notice the order of output from Thread A and Thread B.
|
||||
// - Increase the value passed to the first `sleep_ms()` call in Thread A so that both the
|
||||
// Thread B outputs occur *before* Thread A outputs anything.
|
||||
// - Run the code again and make sure the output comes in a different order.
|
||||
|
||||
// Thread A
|
||||
let handle_a = thread::spawn(move || {
|
||||
sleep_ms(0);
|
||||
tx2.send("Thread A: 1").unwrap();
|
||||
sleep_ms(200);
|
||||
tx2.send("Thread A: 2").unwrap();
|
||||
});
|
||||
// Thread A
|
||||
let handle_a = thread::spawn(move || {
|
||||
sleep_ms(500);
|
||||
tx2.send("Thread A: 1").unwrap();
|
||||
sleep_ms(200);
|
||||
tx2.send("Thread A: 2").unwrap();
|
||||
});
|
||||
|
||||
sleep_ms(100); // Make sure Thread A has time to get going before we spawn Thread B
|
||||
sleep_ms(100); // Make sure Thread A has time to get going before we spawn Thread B
|
||||
|
||||
// Thread B
|
||||
let handle_b = thread::spawn(move || {
|
||||
sleep_ms(0);
|
||||
tx.send("Thread B: 1").unwrap();
|
||||
sleep_ms(200);
|
||||
tx.send("Thread B: 2").unwrap();
|
||||
});
|
||||
// Thread B
|
||||
let handle_b = thread::spawn(move || {
|
||||
sleep_ms(0);
|
||||
tx.send("Thread B: 1").unwrap();
|
||||
sleep_ms(200);
|
||||
tx.send("Thread B: 2").unwrap();
|
||||
});
|
||||
|
||||
// Using a Receiver channel as an iterator is a convenient way to get values until the channel
|
||||
// gets closed. A Receiver channel is automatically closed once all Sender channels have been
|
||||
// closed. Both our threads automatically close their Sender channels when they exit and the
|
||||
// destructors for the channels get automatically called.
|
||||
for msg in rx {
|
||||
println!("Main thread: Received {}", msg);
|
||||
}
|
||||
// Using a Receiver channel as an iterator is a convenient way to get values until the channel
|
||||
// gets closed. A Receiver channel is automatically closed once all Sender channels have been
|
||||
// closed. Both our threads automatically close their Sender channels when they exit and the
|
||||
// destructors for the channels get automatically called.
|
||||
for msg in rx {
|
||||
println!("Main thread: Received {}", msg);
|
||||
}
|
||||
|
||||
// 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene!
|
||||
// - Use the thread handles to join both threads without getting any compiler warnings.
|
||||
*/
|
||||
// 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene!
|
||||
// - Use the thread handles to join both threads without getting any compiler warnings.
|
||||
let _ = handle_a.join();
|
||||
let _ = handle_b.join();
|
||||
|
||||
// Challenge: Make two child threads and give them each a receiving end to a channel. From the
|
||||
// main thread loop through several values and print each out and then send it to the channel.
|
||||
// On the child threads print out the values you receive. Close the sending side in the main
|
||||
// thread by calling `drop(tx)` (assuming you named your sender channel variable `tx`). Join
|
||||
// the child threads.
|
||||
|
||||
let (tx, rx) = channel::unbounded();
|
||||
let rx2 = rx.clone();
|
||||
|
||||
let thread_a_handle = thread::spawn(move || {
|
||||
for n in rx {
|
||||
println!("Thread A received: {}", n);
|
||||
sleep_ms(10);
|
||||
}
|
||||
});
|
||||
|
||||
let thread_b_handle = thread::spawn(move || {
|
||||
for n in rx2 {
|
||||
println!("Thread B received: {}", n);
|
||||
sleep_ms(10);
|
||||
}
|
||||
});
|
||||
|
||||
for number in vec![1, 2, 3, 4, 5] {
|
||||
println!("NUMBER: {}", number);
|
||||
let _ = tx.send(number);
|
||||
}
|
||||
drop(tx);
|
||||
|
||||
let _ = thread_a_handle.join();
|
||||
let _ = thread_b_handle.join();
|
||||
|
||||
println!("Main thread: Exiting.")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,39 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Cake {
|
||||
Chocolate,
|
||||
MapleBacon,
|
||||
Spice,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Party {
|
||||
pub at_restaurant: bool,
|
||||
pub num_people: u8,
|
||||
pub cake: Cake,
|
||||
}
|
||||
|
||||
impl Default for Party {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
at_restaurant: true,
|
||||
num_people: 8,
|
||||
cake: Cake::Chocolate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Party {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cake == other.cake
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Party> for Cake {
|
||||
fn from(party: &Party) -> Self {
|
||||
party.cake
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// 1. The code below doesn't work because Cake doesn't implement Debug.
|
||||
// - Derive the Debug trait for the Cake enum above so this code will work. Then, run the code.
|
||||
@@ -23,11 +47,11 @@ fn main() {
|
||||
// function instead of moved.
|
||||
// - Hint: You may need to derive another trait in order to be able to derive the Copy trait
|
||||
|
||||
// match cake {
|
||||
// Cake::Chocolate => println!("The name's Chocolate. Dark...Chocolate."),
|
||||
// Cake::MapleBacon => println!("Dreams do come true!"),
|
||||
// Cake::Spice => println!("Great, let's spice it up!"),
|
||||
// }
|
||||
match cake {
|
||||
Cake::Chocolate => println!("The name's Chocolate. Dark...Chocolate."),
|
||||
Cake::MapleBacon => println!("Dreams do come true!"),
|
||||
Cake::Spice => println!("Great, let's spice it up!"),
|
||||
}
|
||||
|
||||
// 3. Uncomment the println below. It doesn't work since the Party struct doesn't implement the
|
||||
// Debug or Default traits.
|
||||
@@ -44,7 +68,7 @@ fn main() {
|
||||
// Hint: If you get stuck, there is an example at
|
||||
// https://doc.rust-lang.org/std/default/trait.Default.html#how-can-i-implement-default
|
||||
|
||||
// println!("The default Party is\n{:#?}", Party::default());
|
||||
println!("The default Party is\n{:#?}", Party::default());
|
||||
|
||||
// 4. You prefer Maple Bacon cake. Use "struct update syntax" to create a Party with `cake`
|
||||
// set to `Cake::MapleBacon`, but the rest of the values are default.
|
||||
@@ -52,10 +76,11 @@ fn main() {
|
||||
// Hint: The trick to struct update syntax is specifying the value(s) you want to customize
|
||||
// first and then ending the struct with `..Default::default()` -- but no comma after that!
|
||||
|
||||
// let party = Party {
|
||||
// ...
|
||||
// };
|
||||
// println!("Yes! My party has my favorite {:?} cake!", party.cake);
|
||||
let party = Party {
|
||||
cake: Cake::MapleBacon,
|
||||
..Default::default()
|
||||
};
|
||||
println!("Yes! My party has my favorite {:?} cake!", party.cake);
|
||||
|
||||
// 5. Parties are "equal" if they have the same cake.
|
||||
// - Derive the PartialEq trait for the Cake enum so Cakes can be compared.
|
||||
@@ -63,14 +88,15 @@ fn main() {
|
||||
// then they are equal, no matter the location or number of attendees at the party.
|
||||
// - Uncomment and run the code below.
|
||||
|
||||
// let other_party = Party {
|
||||
// at_restaurant: false,
|
||||
// num_people: 235,
|
||||
// cake: Cake::MapleBacon,
|
||||
// };
|
||||
// if party == other_party {
|
||||
// println!("Your party is just like mine!");
|
||||
// }
|
||||
let other_party = Party {
|
||||
at_restaurant: false,
|
||||
num_people: 235,
|
||||
cake: Cake::MapleBacon,
|
||||
};
|
||||
|
||||
if party == other_party {
|
||||
println!("Your party is just like mine!");
|
||||
}
|
||||
|
||||
// Challenge: You would like to be able to pass a Party struct into the smell_cake() function
|
||||
// which takes a type T which implements the Into<Cake> trait.
|
||||
@@ -78,20 +104,22 @@ fn main() {
|
||||
// - Implement `From<Party> for Cake` so that the function call below works.
|
||||
//
|
||||
|
||||
// smell_cake(party);
|
||||
smell_cake(&party);
|
||||
|
||||
// Challenge 2: Implement `From<&Party> for Cake` so that you can smell your cake without
|
||||
// consuming it. Change the code above to pass in a &party. Then uncomment and run the code
|
||||
// below. After all, you want to smell your cake and eat it, too!
|
||||
|
||||
// println!("Yum! I'm eating this cake: {:?}. Oops, I dropped it on the floor.", party.cake);
|
||||
// drop(cake);
|
||||
println!(
|
||||
"Yum! I'm eating this cake: {:?}. Oops, I dropped it on the floor.",
|
||||
party.cake
|
||||
);
|
||||
}
|
||||
|
||||
pub fn admire_cake(cake: Cake) {
|
||||
println!("What a nice {:?} cake! 🎂", cake);
|
||||
}
|
||||
|
||||
// pub fn smell_cake<T: Into<Cake>>(something: T) {
|
||||
// println!("Hmm...something smells like a {:?} cake!", something.into());
|
||||
// }
|
||||
pub fn smell_cake<T: Into<Cake>>(something: T) {
|
||||
println!("Hmm...something smells like a {:?} cake!", something.into());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user