mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-09 20:03:24 +03:00
Compare commits
13 commits
d768353806
...
3d540ed946
Author | SHA1 | Date | |
---|---|---|---|
3d540ed946 | |||
98cd00de63 | |||
ecbe9b7324 | |||
879f0cd5c6 | |||
613ec23f84 | |||
f574905b8e | |||
bd63ece47c | |||
2901d85662 | |||
020711fa97 | |||
a2dfbd86da | |||
d6fd251a73 | |||
1264510fc0 | |||
ef842d3a94 |
|
@ -1,13 +1,12 @@
|
||||||
// Address all the TODOs to make the tests pass!
|
struct ColorRegularStruct {
|
||||||
|
// TODO: Add the fields that the test `regular_structs` expects.
|
||||||
struct ColorClassicStruct {
|
// What types should the fields have? What are the minimum and maximum values for RGB colors?
|
||||||
// TODO: Something goes here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ColorTupleStruct(/* TODO: Something goes here */);
|
struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct UnitLikeStruct;
|
struct UnitStruct;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// You can optionally experiment here.
|
// You can optionally experiment here.
|
||||||
|
@ -18,8 +17,8 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classic_c_structs() {
|
fn regular_structs() {
|
||||||
// TODO: Instantiate a classic c struct!
|
// TODO: Instantiate a regular struct.
|
||||||
// let green =
|
// let green =
|
||||||
|
|
||||||
assert_eq!(green.red, 0);
|
assert_eq!(green.red, 0);
|
||||||
|
@ -29,7 +28,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuple_structs() {
|
fn tuple_structs() {
|
||||||
// TODO: Instantiate a tuple struct!
|
// TODO: Instantiate a tuple struct.
|
||||||
// let green =
|
// let green =
|
||||||
|
|
||||||
assert_eq!(green.0, 0);
|
assert_eq!(green.0, 0);
|
||||||
|
@ -39,10 +38,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unit_structs() {
|
fn unit_structs() {
|
||||||
// TODO: Instantiate a unit-like struct!
|
// TODO: Instantiate a unit struct.
|
||||||
// let unit_like_struct =
|
// let unit_struct =
|
||||||
let message = format!("{:?}s are fun!", unit_like_struct);
|
let message = format!("{unit_struct:?}s are fun!");
|
||||||
|
|
||||||
assert_eq!(message, "UnitLikeStructs are fun!");
|
assert_eq!(message, "UnitStructs are fun!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// Address all the TODOs to make the tests pass!
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Order {
|
struct Order {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -34,8 +32,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn your_order() {
|
fn your_order() {
|
||||||
let order_template = create_order_template();
|
let order_template = create_order_template();
|
||||||
|
|
||||||
// TODO: Create your own order using the update syntax and template above!
|
// TODO: Create your own order using the update syntax and template above!
|
||||||
// let your_order =
|
// let your_order =
|
||||||
|
|
||||||
assert_eq!(your_order.name, "Hacker in Rust");
|
assert_eq!(your_order.name, "Hacker in Rust");
|
||||||
assert_eq!(your_order.year, order_template.year);
|
assert_eq!(your_order.year, order_template.year);
|
||||||
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
|
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Structs contain data, but can also have logic. In this exercise we have
|
// Structs contain data, but can also have logic. In this exercise we have
|
||||||
// defined the Package struct and we want to test some logic attached to it.
|
// defined the `Package` struct and we want to test some logic attached to it.
|
||||||
// Make the code compile and the tests pass!
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Package {
|
struct Package {
|
||||||
|
@ -10,26 +9,28 @@ struct Package {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package {
|
fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
|
||||||
if weight_in_grams < 10 {
|
if weight_in_grams < 10 {
|
||||||
// This is not how you should handle errors in Rust,
|
// This isn't how you should handle errors in Rust, but we will
|
||||||
// but we will learn about error handling later.
|
// learn about error handling later.
|
||||||
panic!("Can not ship a package with weight below 10 grams.")
|
panic!("Can't ship a package with weight below 10 grams");
|
||||||
} else {
|
}
|
||||||
Package {
|
|
||||||
|
Self {
|
||||||
sender_country,
|
sender_country,
|
||||||
recipient_country,
|
recipient_country,
|
||||||
weight_in_grams,
|
weight_in_grams,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add the correct return type to the function signature.
|
||||||
|
fn is_international(&self) {
|
||||||
|
// TODO: Read the tests that use this method to find out when a package is concidered international.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_international(&self) -> ??? {
|
// TODO: Add the correct return type to the function signature.
|
||||||
// Something goes here...
|
fn get_fees(&self, cents_per_gram: u32) {
|
||||||
}
|
// TODO: Calculate the package's fees.
|
||||||
|
|
||||||
fn get_fees(&self, cents_per_gram: u32) -> ??? {
|
|
||||||
// Something goes here...
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Message {
|
enum Message {
|
||||||
// TODO: define a few types of messages as used below
|
// TODO: Define a few types of messages as used below.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Message {
|
enum Message {
|
||||||
// TODO: define the different variants used below
|
// TODO: Define the different variants used below.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Address all the TODOs to make the tests pass!
|
|
||||||
|
|
||||||
enum Message {
|
enum Message {
|
||||||
// TODO: implement the message variant types based on their usage below
|
// TODO: Implement the message variant types based on their usage below.
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Point {
|
struct Point {
|
||||||
|
@ -26,17 +24,17 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo(&mut self, s: String) {
|
fn echo(&mut self, s: String) {
|
||||||
self.message = s
|
self.message = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_position(&mut self, p: Point) {
|
fn move_position(&mut self, point: Point) {
|
||||||
self.position = p;
|
self.position = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, message: Message) {
|
fn process(&mut self, message: Message) {
|
||||||
// TODO: create a match expression to process the different message variants
|
// TODO: Create a match expression to process the different message variants.
|
||||||
// Remember: When passing a tuple as a function argument, you'll need extra parentheses:
|
// Remember: When passing a tuple as a function argument, you'll need extra parentheses:
|
||||||
// fn function((t, u, p, l, e))
|
// e.g. `foo((t, u, p, l, e))`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +52,9 @@ mod tests {
|
||||||
quit: false,
|
quit: false,
|
||||||
position: Point { x: 0, y: 0 },
|
position: Point { x: 0, y: 0 },
|
||||||
color: (0, 0, 0),
|
color: (0, 0, 0),
|
||||||
message: "hello world".to_string(),
|
message: String::from("hello world"),
|
||||||
};
|
};
|
||||||
|
|
||||||
state.process(Message::ChangeColor(255, 0, 255));
|
state.process(Message::ChangeColor(255, 0, 255));
|
||||||
state.process(Message::Echo(String::from("Hello world!")));
|
state.process(Message::Echo(String::from("Hello world!")));
|
||||||
state.process(Message::Move(Point { x: 10, y: 15 }));
|
state.process(Message::Move(Point { x: 10, y: 15 }));
|
||||||
|
@ -64,7 +63,7 @@ mod tests {
|
||||||
assert_eq!(state.color, (255, 0, 255));
|
assert_eq!(state.color, (255, 0, 255));
|
||||||
assert_eq!(state.position.x, 10);
|
assert_eq!(state.position.x, 10);
|
||||||
assert_eq!(state.position.y, 15);
|
assert_eq!(state.position.y, 15);
|
||||||
assert_eq!(state.quit, true);
|
assert!(state.quit);
|
||||||
assert_eq!(state.message, "Hello world!");
|
assert_eq!(state.message, "Hello world!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// Make me compile without changing the function signature!
|
// TODO: Fix the compiler error without changing the function signature.
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let answer = current_favorite_color();
|
|
||||||
println!("My current favorite color is {}", answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_favorite_color() -> String {
|
fn current_favorite_color() -> String {
|
||||||
"blue"
|
"blue"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let answer = current_favorite_color();
|
||||||
|
println!("My current favorite color is {answer}");
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// Make me compile without changing the function signature!
|
// TODO: Fix the compiler error in the `main` function without changing this function.
|
||||||
|
fn is_a_color_word(attempt: &str) -> bool {
|
||||||
|
attempt == "green" || attempt == "blue" || attempt == "red"
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let word = String::from("green"); // Try not changing this line :)
|
let word = String::from("green"); // Don't change this line.
|
||||||
|
|
||||||
if is_a_color_word(word) {
|
if is_a_color_word(word) {
|
||||||
println!("That is a color word I know!");
|
println!("That is a color word I know!");
|
||||||
} else {
|
} else {
|
||||||
println!("That is not a color word I know.");
|
println!("That is not a color word I know.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_a_color_word(attempt: &str) -> bool {
|
|
||||||
attempt == "green" || attempt == "blue" || attempt == "red"
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
fn trim_me(input: &str) -> String {
|
fn trim_me(input: &str) -> &str {
|
||||||
// TODO: Remove whitespace from both ends of a string!
|
// TODO: Remove whitespace from both ends of a string.
|
||||||
???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compose_me(input: &str) -> String {
|
fn compose_me(input: &str) -> String {
|
||||||
// TODO: Add " world!" to the string! There are multiple ways to do this!
|
// TODO: Add " world!" to the string! There are multiple ways to do this.
|
||||||
???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_me(input: &str) -> String {
|
fn replace_me(input: &str) -> String {
|
||||||
// TODO: Replace "cars" in the string with "balloons"!
|
// TODO: Replace "cars" in the string with "balloons".
|
||||||
???
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -36,7 +33,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replace_a_string() {
|
fn replace_a_string() {
|
||||||
assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool");
|
assert_eq!(
|
||||||
assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons");
|
replace_me("I think cars are cool"),
|
||||||
|
"I think balloons are cool",
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
replace_me("I love to look at cars"),
|
||||||
|
"I love to look at balloons",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
// Ok, here are a bunch of values - some are `String`s, some are `&str`s. Your
|
// Calls of this function should be replaced with calls of `string_slice` or `string`.
|
||||||
// task is to call one of these two functions on each value depending on what
|
fn placeholder() {}
|
||||||
// you think each value is. That is, add either `string_slice` or `string`
|
|
||||||
// before the parentheses on each line. If you're right, it will compile!
|
|
||||||
|
|
||||||
fn string_slice(arg: &str) {
|
fn string_slice(arg: &str) {
|
||||||
println!("{}", arg);
|
println!("{arg}");
|
||||||
}
|
}
|
||||||
fn string(arg: String) {
|
fn string(arg: String) {
|
||||||
println!("{}", arg);
|
println!("{arg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Here are a bunch of values - some are `String`, some are `&str`.
|
||||||
|
// Your task is to replace `placeholder(…)` with either `string_slice(…)`
|
||||||
|
// or `string(…)` depending on what you think each value is.
|
||||||
fn main() {
|
fn main() {
|
||||||
???("blue");
|
placeholder("blue");
|
||||||
???("red".to_string());
|
|
||||||
???(String::from("hi"));
|
placeholder("red".to_string());
|
||||||
???("rust is fun!".to_owned());
|
|
||||||
???("nice weather".into());
|
placeholder(String::from("hi"));
|
||||||
???(format!("Interpolation {}", "Station"));
|
|
||||||
???(&String::from("abc")[0..1]);
|
placeholder("rust is fun!".to_owned());
|
||||||
???(" hello there ".trim());
|
|
||||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
placeholder("nice weather".into());
|
||||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
|
||||||
|
placeholder(format!("Interpolation {}", "Station"));
|
||||||
|
|
||||||
|
// WARNING: This is byte indexing, not character indexing.
|
||||||
|
// Character indexing can be done using `s.chars().nth(INDEX)`.
|
||||||
|
placeholder(&String::from("abc")[0..1]);
|
||||||
|
|
||||||
|
placeholder(" hello there ".trim());
|
||||||
|
|
||||||
|
placeholder("Happy Monday!".replace("Mon", "Tues"));
|
||||||
|
|
||||||
|
placeholder("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// TODO: Fix the compiler error about calling a private function.
|
||||||
mod sausage_factory {
|
mod sausage_factory {
|
||||||
// Don't let anybody outside of this module see this!
|
// Don't let anybody outside of this module see this!
|
||||||
fn get_secret_recipe() -> String {
|
fn get_secret_recipe() -> String {
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
// You can bring module paths into scopes and provide new names for them with
|
// You can bring module paths into scopes and provide new names for them with
|
||||||
// the 'use' and 'as' keywords. Fix these 'use' statements to make the code
|
// the `use` and `as` keywords.
|
||||||
// compile.
|
|
||||||
|
|
||||||
mod delicious_snacks {
|
mod delicious_snacks {
|
||||||
// TODO: Fix these use statements
|
// TODO: Add the follwing two `use` statements after fixing them.
|
||||||
use self::fruits::PEAR as ???
|
// use self::fruits::PEAR as ???;
|
||||||
use self::veggies::CUCUMBER as ???
|
// use self::veggies::CUCUMBER as ???;
|
||||||
|
|
||||||
mod fruits {
|
mod fruits {
|
||||||
pub const PEAR: &'static str = "Pear";
|
pub const PEAR: &str = "Pear";
|
||||||
pub const APPLE: &'static str = "Apple";
|
pub const APPLE: &str = "Apple";
|
||||||
}
|
}
|
||||||
|
|
||||||
mod veggies {
|
mod veggies {
|
||||||
pub const CUCUMBER: &'static str = "Cucumber";
|
pub const CUCUMBER: &str = "Cucumber";
|
||||||
pub const CARROT: &'static str = "Carrot";
|
pub const CARROT: &str = "Carrot";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +21,6 @@ fn main() {
|
||||||
println!(
|
println!(
|
||||||
"favorite snacks: {} and {}",
|
"favorite snacks: {} and {}",
|
||||||
delicious_snacks::fruit,
|
delicious_snacks::fruit,
|
||||||
delicious_snacks::veggie
|
delicious_snacks::veggie,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// You can use the 'use' keyword to bring module paths from modules from
|
// You can use the `use` keyword to bring module paths from modules from
|
||||||
// anywhere and especially from the Rust standard library into your scope. Bring
|
// anywhere and especially from the standard library into your scope.
|
||||||
// SystemTime and UNIX_EPOCH from the std::time module. Bonus style points if
|
|
||||||
// you can do it with one line!
|
|
||||||
|
|
||||||
// TODO: Complete this use statement
|
// TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into
|
||||||
use ???
|
// your scope. Bonus style points if you can do it with one line!
|
||||||
|
// use ???;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match SystemTime::now().duration_since(UNIX_EPOCH) {
|
match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||||
|
|
|
@ -402,15 +402,14 @@ hint = """
|
||||||
Rust has more than one type of struct. Three actually, all variants are used to
|
Rust has more than one type of struct. Three actually, all variants are used to
|
||||||
package related data together.
|
package related data together.
|
||||||
|
|
||||||
There are normal (or classic) structs. These are named collections of related
|
There are regular structs. These are named collections of related data stored in
|
||||||
data stored in fields.
|
fields.
|
||||||
|
|
||||||
Tuple structs are basically just named tuples.
|
Tuple structs are basically just named tuples.
|
||||||
|
|
||||||
Finally, Unit-like structs. These don't have any fields and are useful for
|
Finally, unit structs. These don't have any fields and are useful for generics.
|
||||||
generics.
|
|
||||||
|
|
||||||
In this exercise you need to complete and implement one of each kind.
|
In this exercise, you need to complete and implement one of each kind.
|
||||||
Read more about structs in The Book:
|
Read more about structs in The Book:
|
||||||
https://doc.rust-lang.org/book/ch05-01-defining-structs.html"""
|
https://doc.rust-lang.org/book/ch05-01-defining-structs.html"""
|
||||||
|
|
||||||
|
@ -422,7 +421,7 @@ Creating instances of structs is easy, all you need to do is assign some values
|
||||||
to its fields.
|
to its fields.
|
||||||
|
|
||||||
There are however some shortcuts that can be taken when instantiating structs.
|
There are however some shortcuts that can be taken when instantiating structs.
|
||||||
Have a look in The Book, to find out more:
|
Have a look in The Book to find out more:
|
||||||
https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax"""
|
https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax"""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
|
@ -435,7 +434,7 @@ the places it goes through right?
|
||||||
For `get_fees`: This method takes an additional argument, is there a field in
|
For `get_fees`: This method takes an additional argument, is there a field in
|
||||||
the `Package` struct that this relates to?
|
the `Package` struct that this relates to?
|
||||||
|
|
||||||
Have a look in The Book, to find out more about method implementations:
|
Have a look in The Book to find out more about method implementations:
|
||||||
https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
|
https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
|
||||||
|
|
||||||
# ENUMS
|
# ENUMS
|
||||||
|
@ -452,18 +451,18 @@ dir = "08_enums"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
You can create enumerations that have different variants with different types
|
You can create enumerations that have different variants with different types
|
||||||
such as no data, anonymous structs, a single string, tuples, ...etc"""
|
such as no data, anonymous structs, a single string, tuples, etc."""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "enums3"
|
name = "enums3"
|
||||||
dir = "08_enums"
|
dir = "08_enums"
|
||||||
hint = """
|
hint = """
|
||||||
As a first step, you can define enums to compile this code without errors.
|
As a first step, define enums to compile the code without errors.
|
||||||
|
|
||||||
And then create a match expression in `process()`.
|
Then, create a match expression in `process()`.
|
||||||
|
|
||||||
Note that you need to deconstruct some message variants in the match expression
|
Note that you need to deconstruct some message variants in the match expression
|
||||||
to get value in the variant."""
|
to get the variant's values."""
|
||||||
|
|
||||||
# STRINGS
|
# STRINGS
|
||||||
|
|
||||||
|
@ -487,7 +486,7 @@ dir = "09_strings"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
Yes, it would be really easy to fix this by just changing the value bound to
|
Yes, it would be really easy to fix this by just changing the value bound to
|
||||||
`word` to be a string slice instead of a `String`, wouldn't it?? There is a way
|
`word` to be a string slice instead of a `String`, wouldn't it? There is a way
|
||||||
to add one character to the `if` statement, though, that will coerce the
|
to add one character to the `if` statement, though, that will coerce the
|
||||||
`String` into a string slice.
|
`String` into a string slice.
|
||||||
|
|
||||||
|
@ -500,7 +499,8 @@ https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercion
|
||||||
name = "strings3"
|
name = "strings3"
|
||||||
dir = "09_strings"
|
dir = "09_strings"
|
||||||
hint = """
|
hint = """
|
||||||
There's tons of useful standard library functions for strings. Let's try and use some of them:
|
There are many useful standard library functions for strings. Let's try and use
|
||||||
|
some of them:
|
||||||
https://doc.rust-lang.org/std/string/struct.String.html#method.trim
|
https://doc.rust-lang.org/std/string/struct.String.html#method.trim
|
||||||
|
|
||||||
For the `compose_me` method: You can either use the `format!` macro, or convert
|
For the `compose_me` method: You can either use the `format!` macro, or convert
|
||||||
|
@ -510,7 +510,15 @@ the string slice into an owned string, which you can then freely extend."""
|
||||||
name = "strings4"
|
name = "strings4"
|
||||||
dir = "09_strings"
|
dir = "09_strings"
|
||||||
test = false
|
test = false
|
||||||
hint = "No hints this time ;)"
|
hint = """
|
||||||
|
Replace `placeholder` with either `string` or `string_slice` in the `main` function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`placeholder("blue");`
|
||||||
|
should become
|
||||||
|
`string_slice("blue");`
|
||||||
|
because "blue" is `&str`, not `String`.
|
||||||
|
"""
|
||||||
|
|
||||||
# MODULES
|
# MODULES
|
||||||
|
|
||||||
|
@ -519,21 +527,21 @@ name = "modules1"
|
||||||
dir = "10_modules"
|
dir = "10_modules"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
Everything is private in Rust by default-- but there's a keyword we can use
|
Everything is private in Rust by default. But there's a keyword we can use
|
||||||
to make something public! The compiler error should point to the thing that
|
to make something public!"""
|
||||||
needs to be public."""
|
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "modules2"
|
name = "modules2"
|
||||||
dir = "10_modules"
|
dir = "10_modules"
|
||||||
test = false
|
test = false
|
||||||
hint = """
|
hint = """
|
||||||
The delicious_snacks module is trying to present an external interface that is
|
The `delicious_snacks` module is trying to present an external interface that
|
||||||
different than its internal structure (the `fruits` and `veggies` modules and
|
is different than its internal structure (the `fruits` and `veggies` modules
|
||||||
associated constants). Complete the `use` statements to fit the uses in main and
|
and associated constants). Complete the `use` statements to fit the uses in
|
||||||
find the one keyword missing for both constants.
|
`main` and find the one keyword missing for both constants.
|
||||||
|
|
||||||
Learn more at https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#re-exporting-names-with-pub-use"""
|
Learn more in The Book:
|
||||||
|
https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#re-exporting-names-with-pub-use"""
|
||||||
|
|
||||||
[[exercises]]
|
[[exercises]]
|
||||||
name = "modules3"
|
name = "modules3"
|
||||||
|
@ -542,7 +550,7 @@ test = false
|
||||||
hint = """
|
hint = """
|
||||||
`UNIX_EPOCH` and `SystemTime` are declared in the `std::time` module. Add a
|
`UNIX_EPOCH` and `SystemTime` are declared in the `std::time` module. Add a
|
||||||
`use` statement for these two to bring them into scope. You can use nested
|
`use` statement for these two to bring them into scope. You can use nested
|
||||||
paths or the glob operator to bring these two in using only one line."""
|
paths to bring these two in using only one line."""
|
||||||
|
|
||||||
# HASHMAPS
|
# HASHMAPS
|
||||||
|
|
||||||
|
|
|
@ -1 +1,49 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
struct ColorRegularStruct {
|
||||||
|
red: u8,
|
||||||
|
green: u8,
|
||||||
|
blue: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColorTupleStruct(u8, u8, u8);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UnitStruct;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regular_structs() {
|
||||||
|
let green = ColorRegularStruct {
|
||||||
|
red: 0,
|
||||||
|
green: 255,
|
||||||
|
blue: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(green.red, 0);
|
||||||
|
assert_eq!(green.green, 255);
|
||||||
|
assert_eq!(green.blue, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_structs() {
|
||||||
|
let green = ColorTupleStruct(0, 255, 0);
|
||||||
|
|
||||||
|
assert_eq!(green.0, 0);
|
||||||
|
assert_eq!(green.1, 255);
|
||||||
|
assert_eq!(green.2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit_structs() {
|
||||||
|
let unit_struct = UnitStruct;
|
||||||
|
let message = format!("{unit_struct:?}s are fun!");
|
||||||
|
|
||||||
|
assert_eq!(message, "UnitStructs are fun!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,51 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
#[derive(Debug)]
|
||||||
|
struct Order {
|
||||||
|
name: String,
|
||||||
|
year: u32,
|
||||||
|
made_by_phone: bool,
|
||||||
|
made_by_mobile: bool,
|
||||||
|
made_by_email: bool,
|
||||||
|
item_number: u32,
|
||||||
|
count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_order_template() -> Order {
|
||||||
|
Order {
|
||||||
|
name: String::from("Bob"),
|
||||||
|
year: 2019,
|
||||||
|
made_by_phone: false,
|
||||||
|
made_by_mobile: false,
|
||||||
|
made_by_email: true,
|
||||||
|
item_number: 123,
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn your_order() {
|
||||||
|
let order_template = create_order_template();
|
||||||
|
|
||||||
|
let your_order = Order {
|
||||||
|
name: String::from("Hacker in Rust"),
|
||||||
|
count: 1,
|
||||||
|
// Struct update syntax
|
||||||
|
..order_template
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(your_order.name, "Hacker in Rust");
|
||||||
|
assert_eq!(your_order.year, order_template.year);
|
||||||
|
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
|
||||||
|
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
|
||||||
|
assert_eq!(your_order.made_by_email, order_template.made_by_email);
|
||||||
|
assert_eq!(your_order.item_number, order_template.item_number);
|
||||||
|
assert_eq!(your_order.count, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,83 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
#[derive(Debug)]
|
||||||
|
struct Package {
|
||||||
|
sender_country: String,
|
||||||
|
recipient_country: String,
|
||||||
|
weight_in_grams: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Package {
|
||||||
|
fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
|
||||||
|
if weight_in_grams < 10 {
|
||||||
|
// This isn't how you should handle errors in Rust, but we will
|
||||||
|
// learn about error handling later.
|
||||||
|
panic!("Can't ship a package with weight below 10 grams");
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sender_country,
|
||||||
|
recipient_country,
|
||||||
|
weight_in_grams,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_international(&self) -> bool {
|
||||||
|
// ^^^^^^^ added
|
||||||
|
self.sender_country != self.recipient_country
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fees(&self, cents_per_gram: u32) -> u32 {
|
||||||
|
// ^^^^^^ added
|
||||||
|
self.weight_in_grams * cents_per_gram
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn fail_creating_weightless_package() {
|
||||||
|
let sender_country = String::from("Spain");
|
||||||
|
let recipient_country = String::from("Austria");
|
||||||
|
|
||||||
|
Package::new(sender_country, recipient_country, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_international_package() {
|
||||||
|
let sender_country = String::from("Spain");
|
||||||
|
let recipient_country = String::from("Russia");
|
||||||
|
|
||||||
|
let package = Package::new(sender_country, recipient_country, 1200);
|
||||||
|
|
||||||
|
assert!(package.is_international());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_local_package() {
|
||||||
|
let sender_country = String::from("Canada");
|
||||||
|
let recipient_country = sender_country.clone();
|
||||||
|
|
||||||
|
let package = Package::new(sender_country, recipient_country, 1200);
|
||||||
|
|
||||||
|
assert!(!package.is_international());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calculate_transport_fees() {
|
||||||
|
let sender_country = String::from("Spain");
|
||||||
|
let recipient_country = String::from("Spain");
|
||||||
|
|
||||||
|
let cents_per_gram = 3;
|
||||||
|
|
||||||
|
let package = Package::new(sender_country, recipient_country, 1500);
|
||||||
|
|
||||||
|
assert_eq!(package.get_fees(cents_per_gram), 4500);
|
||||||
|
assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,14 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
#[derive(Debug)]
|
||||||
|
enum Message {
|
||||||
|
Quit,
|
||||||
|
Echo,
|
||||||
|
Move,
|
||||||
|
ChangeColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{:?}", Message::Quit);
|
||||||
|
println!("{:?}", Message::Echo);
|
||||||
|
println!("{:?}", Message::Move);
|
||||||
|
println!("{:?}", Message::ChangeColor);
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,26 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
#[derive(Debug)]
|
||||||
|
enum Message {
|
||||||
|
Move { x: i64, y: i64 },
|
||||||
|
Echo(String),
|
||||||
|
ChangeColor(u8, u8, u8),
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
fn call(&self) {
|
||||||
|
println!("{:?}", self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let messages = [
|
||||||
|
Message::Move { x: 10, y: 30 },
|
||||||
|
Message::Echo(String::from("hello world")),
|
||||||
|
Message::ChangeColor(200, 255, 255),
|
||||||
|
Message::Quit,
|
||||||
|
];
|
||||||
|
|
||||||
|
for message in &messages {
|
||||||
|
message.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,75 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
enum Message {
|
||||||
|
ChangeColor(u8, u8, u8),
|
||||||
|
Echo(String),
|
||||||
|
Move(Point),
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
x: u8,
|
||||||
|
y: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
color: (u8, u8, u8),
|
||||||
|
position: Point,
|
||||||
|
quit: bool,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn change_color(&mut self, color: (u8, u8, u8)) {
|
||||||
|
self.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quit(&mut self) {
|
||||||
|
self.quit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn echo(&mut self, s: String) {
|
||||||
|
self.message = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_position(&mut self, point: Point) {
|
||||||
|
self.position = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(&mut self, message: Message) {
|
||||||
|
match message {
|
||||||
|
Message::ChangeColor(r, g, b) => self.change_color((r, g, b)),
|
||||||
|
Message::Echo(s) => self.echo(s),
|
||||||
|
Message::Move(point) => self.move_position(point),
|
||||||
|
Message::Quit => self.quit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_match_message_call() {
|
||||||
|
let mut state = State {
|
||||||
|
quit: false,
|
||||||
|
position: Point { x: 0, y: 0 },
|
||||||
|
color: (0, 0, 0),
|
||||||
|
message: String::from("hello world"),
|
||||||
|
};
|
||||||
|
|
||||||
|
state.process(Message::ChangeColor(255, 0, 255));
|
||||||
|
state.process(Message::Echo(String::from("Hello world!")));
|
||||||
|
state.process(Message::Move(Point { x: 10, y: 15 }));
|
||||||
|
state.process(Message::Quit);
|
||||||
|
|
||||||
|
assert_eq!(state.color, (255, 0, 255));
|
||||||
|
assert_eq!(state.position.x, 10);
|
||||||
|
assert_eq!(state.position.y, 15);
|
||||||
|
assert!(state.quit);
|
||||||
|
assert_eq!(state.message, "Hello world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,9 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
fn current_favorite_color() -> String {
|
||||||
|
// Equivalent to `String::from("blue")`
|
||||||
|
"blue".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let answer = current_favorite_color();
|
||||||
|
println!("My current favorite color is {answer}");
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
fn is_a_color_word(attempt: &str) -> bool {
|
||||||
|
attempt == "green" || attempt == "blue" || attempt == "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let word = String::from("green");
|
||||||
|
|
||||||
|
if is_a_color_word(&word) {
|
||||||
|
// ^ added to have `&String` which is automatically
|
||||||
|
// coerced to `&str` by the compiler.
|
||||||
|
println!("That is a color word I know!");
|
||||||
|
} else {
|
||||||
|
println!("That is not a color word I know.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,48 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
fn trim_me(input: &str) -> &str {
|
||||||
|
input.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compose_me(input: &str) -> String {
|
||||||
|
// The macro `format!` has the same syntax as `println!`, but it returns a
|
||||||
|
// string instead of printing it to the terminal.
|
||||||
|
// Equivalent to `input.to_string() + " world!"`
|
||||||
|
format!("{input} world!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_me(input: &str) -> String {
|
||||||
|
input.replace("cars", "balloons")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// You can optionally experiment here.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trim_a_string() {
|
||||||
|
assert_eq!(trim_me("Hello! "), "Hello!");
|
||||||
|
assert_eq!(trim_me(" What's up!"), "What's up!");
|
||||||
|
assert_eq!(trim_me(" Hola! "), "Hola!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compose_a_string() {
|
||||||
|
assert_eq!(compose_me("Hello"), "Hello world!");
|
||||||
|
assert_eq!(compose_me("Goodbye"), "Goodbye world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_a_string() {
|
||||||
|
assert_eq!(
|
||||||
|
replace_me("I think cars are cool"),
|
||||||
|
"I think balloons are cool",
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
replace_me("I love to look at cars"),
|
||||||
|
"I love to look at balloons",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,38 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
fn string_slice(arg: &str) {
|
||||||
|
println!("{arg}");
|
||||||
|
}
|
||||||
|
fn string(arg: String) {
|
||||||
|
println!("{arg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
string_slice("blue");
|
||||||
|
|
||||||
|
string("red".to_string());
|
||||||
|
|
||||||
|
string(String::from("hi"));
|
||||||
|
|
||||||
|
string("rust is fun!".to_owned());
|
||||||
|
|
||||||
|
// Here, both answers work.
|
||||||
|
// `.into()` converts a type into an expected type.
|
||||||
|
// If it is called where `String` is expected, it will convert `&str` to `String`.
|
||||||
|
// But if is called where `&str` is expected, then `&str` is kept `&str` since no
|
||||||
|
// conversion is needed.
|
||||||
|
string("nice weather".into());
|
||||||
|
string_slice("nice weather".into());
|
||||||
|
// ^^^^^^^ the compiler recommends removing the `.into()`
|
||||||
|
// call because it is a useless conversion.
|
||||||
|
|
||||||
|
string(format!("Interpolation {}", "Station"));
|
||||||
|
|
||||||
|
// WARNING: This is byte indexing, not character indexing.
|
||||||
|
// Character indexing can be done using `s.chars().nth(INDEX)`.
|
||||||
|
string_slice(&String::from("abc")[0..1]);
|
||||||
|
|
||||||
|
string_slice(" hello there ".trim());
|
||||||
|
|
||||||
|
string("Happy Monday!".replace("Mon", "Tues"));
|
||||||
|
|
||||||
|
string("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
mod sausage_factory {
|
||||||
|
fn get_secret_recipe() -> String {
|
||||||
|
String::from("Ginger")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added `pub` before `fn` to make the function accessible outside the module.
|
||||||
|
pub fn make_sausage() {
|
||||||
|
get_secret_recipe();
|
||||||
|
println!("sausage!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
sausage_factory::make_sausage();
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,23 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
mod delicious_snacks {
|
||||||
|
// Added `pub` and used the expected alias after `as`.
|
||||||
|
pub use self::fruits::PEAR as fruit;
|
||||||
|
pub use self::veggies::CUCUMBER as veggie;
|
||||||
|
|
||||||
|
mod fruits {
|
||||||
|
pub const PEAR: &str = "Pear";
|
||||||
|
pub const APPLE: &str = "Apple";
|
||||||
|
}
|
||||||
|
|
||||||
|
mod veggies {
|
||||||
|
pub const CUCUMBER: &str = "Cucumber";
|
||||||
|
pub const CARROT: &str = "Carrot";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!(
|
||||||
|
"favorite snacks: {} and {}",
|
||||||
|
delicious_snacks::fruit,
|
||||||
|
delicious_snacks::veggie,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,8 @@
|
||||||
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||||
|
Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
|
||||||
|
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue