diff options
| author | olivia <olivia@fastmail.com> | 2018-11-09 20:31:14 +0100 |
|---|---|---|
| committer | olivia <olivia@fastmail.com> | 2018-11-09 20:31:14 +0100 |
| commit | f7846af7ac388652a6f80a2bbce926ba8f053062 (patch) | |
| tree | 954ee36257047ac612654c5f35e18ed27deda97f /exercises | |
| parent | 850a13e9133fedb2fce27884902e0aab94da9692 (diff) | |
right let's try this one again
Diffstat (limited to 'exercises')
48 files changed, 2372 insertions, 0 deletions
diff --git a/exercises/error_handling/errors1.rs b/exercises/error_handling/errors1.rs new file mode 100755 index 0000000..14ed574 --- /dev/null +++ b/exercises/error_handling/errors1.rs @@ -0,0 +1,73 @@ +// errors1.rs +// This function refuses to generate text to be printed on a nametag if +// you pass it an empty string. It'd be nicer if it explained what the problem +// was, instead of just sometimes returning `None`. The 2nd test currently +// does not compile or pass, but it illustrates the behavior we would like +// this function to have. +// Scroll down for hints!!! + +pub fn generate_nametag_text(name: String) -> Option<String> { + if name.len() > 0 { + Some(format!("Hi! My name is {}", name)) + } else { + // Empty names aren't allowed. + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // This test passes initially if you comment out the 2nd test. + // You'll need to update what this test expects when you change + // the function under test! + #[test] + fn generates_nametag_text_for_a_nonempty_name() { + assert_eq!( + generate_nametag_text("Beyoncé".into()), + Some("Hi! My name is Beyoncé".into()) + ); + } + + #[test] + fn explains_why_generating_nametag_text_fails() { + assert_eq!( + generate_nametag_text("".into()), + Err("`name` was empty; it must be nonempty.".into()) + ); + } +} + + + + + + + + + + + + + + + + + + + + +// `Err` is one of the variants of `Result`, so what the 2nd test is saying +// is that `generate_nametag_text` should return a `Result` instead of an +// `Option`. + +// To make this change, you'll need to: +// - update the return type in the function signature to be a Result that +// could be the variants `Ok(String)` and `Err(String)` +// - change the body of the function to return `Ok(stuff)` where it currently +// returns `Some(stuff)` +// - change the body of the function to return `Err(error message)` where it +// currently returns `None` +// - change the first test to expect `Ok(stuff)` where it currently expects +// `Some(stuff)`. diff --git a/exercises/error_handling/errors2.rs b/exercises/error_handling/errors2.rs new file mode 100755 index 0000000..15c21c8 --- /dev/null +++ b/exercises/error_handling/errors2.rs @@ -0,0 +1,72 @@ +// errors2.rs +// Say we're writing a game where you can buy items with tokens. All items cost +// 5 tokens, and whenever you purchase items there is a processing fee of 1 +// token. A player of the game will type in how many items they want to buy, +// and the `total_cost` function will calculate the total number of tokens. +// Since the player typed in the quantity, though, we get it as a string-- and +// they might have typed anything, not just numbers! + +// Right now, this function isn't handling the error case at all (and isn't +// handling the success case properly either). What we want to do is: +// if we call the `parse` function on a string that is not a number, that +// function will return a `ParseIntError`, and in that case, we want to +// immediately return that error from our function and not try to multiply +// and add. + +// There are at least two ways to implement this that are both correct-- but +// one is a lot shorter! Scroll down for hints to both ways. + +use std::num::ParseIntError; + +pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> { + let processing_fee = 1; + let cost_per_item = 5; + let qty = item_quantity.parse::<i32>(); + + Ok(qty * cost_per_item + processing_fee) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn item_quantity_is_a_valid_number() { + assert_eq!( + total_cost("34"), + Ok(171) + ); + } + + #[test] + fn item_quantity_is_an_invalid_number() { + assert_eq!( + total_cost("beep boop").unwrap_err().to_string(), + "invalid digit found in string" + ); + } +} + + + + + + + + + + + + + + + + + +// One way to handle this is using a `match` statement on +// `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and +// `Err(something)`. This pattern is very common in Rust, though, so there's +// a `?` operator that does pretty much what you would make that match statement +// do for you! Take a look at this section of the Error Handling chapter: +// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator +// and give it a try! diff --git a/exercises/error_handling/errors3.rs b/exercises/error_handling/errors3.rs new file mode 100755 index 0000000..9c29af5 --- /dev/null +++ b/exercises/error_handling/errors3.rs @@ -0,0 +1,62 @@ +// errors3.rs +// This is a program that is trying to use a completed version of the +// `total_cost` function from the previous exercise. It's not working though-- +// we can't use the `?` operator in the `main()` function! Why not? +// What should we do instead? Scroll for hints! + +use std::num::ParseIntError; + +fn main() { + let mut tokens = 100; + let pretend_user_input = "8"; + + let cost = total_cost(pretend_user_input)?; + + if cost > tokens { + println!("You can't afford that many!"); + } else { + tokens -= cost; + println!("You now have {} tokens.", tokens); + } +} + +pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> { + let processing_fee = 1; + let cost_per_item = 5; + let qty = item_quantity.parse::<i32>()?; + + Ok(qty * cost_per_item + processing_fee) +} + + + + + + + + + + + + + + + + + + +// Since the `?` operator returns an `Err` early if the thing it's trying to +// do fails, you can only use the `?` operator in functions that have a +// `Result` as their return type. + +// Hence the error that you get if you run this code is: + +// ``` +// error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) +// ``` + +// So we have to use another way of handling a `Result` within `main`. + +// Decide what we should do if `pretend_user_input` has a string value that does +// not parse to an integer, and implement that instead of using the `?` +// operator. diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs new file mode 100755 index 0000000..15c6cd5 --- /dev/null +++ b/exercises/error_handling/errorsn.rs @@ -0,0 +1,138 @@ +// errorsn.rs +// This is a bigger error exercise than the previous ones! +// You can do it! :) +// +// Edit the `read_and_validate` function so that it compiles and +// passes the tests... so many things could go wrong! +// +// - Reading from stdin could produce an io::Error +// - Parsing the input could produce a num::ParseIntError +// - Validating the input could produce a CreationError (defined below) +// +// How can we lump these errors into one general error? That is, what +// type goes where the question marks are, and how do we return +// that type from the body of read_and_validate? +// +// Scroll down for hints :) + +use std::error; +use std::fmt; +use std::io; + +// PositiveNonzeroInteger is a struct defined below the tests. +fn read_and_validate(b: &mut io::BufRead) -> Result<PositiveNonzeroInteger, ???> { + let mut line = String::new(); + b.read_line(&mut line); + let num: i64 = line.trim().parse(); + let answer = PositiveNonzeroInteger::new(num); + answer +} + +// This is a test helper function that turns a &str into a BufReader. +fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<error::Error>> { + let mut b = io::BufReader::new(s.as_bytes()); + read_and_validate(&mut b) +} + +#[test] +fn test_success() { + let x = test_with_str("42\n"); + assert_eq!(PositiveNonzeroInteger(42), x.unwrap()); +} + +#[test] +fn test_not_num() { + let x = test_with_str("eleven billion\n"); + assert!(x.is_err()); +} + +#[test] +fn test_non_positive() { + let x = test_with_str("-40\n"); + assert!(x.is_err()); +} + +#[test] +fn test_ioerror() { + struct Broken; + impl io::Read for Broken { + fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { + Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!")) + } + } + let mut b = io::BufReader::new(Broken); + assert!(read_and_validate(&mut b).is_err()); + assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string()); +} + +#[derive(PartialEq,Debug)] +struct PositiveNonzeroInteger(u64); + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { + if value == 0 { + Err(CreationError::Zero) + } else if value < 0 { + Err(CreationError::Negative) + } else { + Ok(PositiveNonzeroInteger(value as u64)) + } + } +} + +#[test] +fn test_positive_nonzero_integer_creation() { + assert!(PositiveNonzeroInteger::new(10).is_ok()); + assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10)); + assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); +} + +#[derive(PartialEq,Debug)] +enum CreationError { + Negative, + Zero, +} + +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str((self as &error::Error).description()) + } +} + +impl error::Error for CreationError { + fn description(&self) -> &str { + match *self { + CreationError::Negative => "Negative", + CreationError::Zero => "Zero", + } + } +} + +// First hint: To figure out what type should go where the ??? is, take a look +// at the test helper function `test_with_str`, since it returns whatever +// `read_and_validate` returns and`test_with_str` has its signature fully +// specified. + +// Next hint: There are three places in `read_and_validate` that we call a +// function that returns a `Result` (that is, the functions might fail). +// Apply the `?` operator on those calls so that we return immediately from +// `read_and_validate` if those function calls fail. + +// Another hint: under the hood, the `?` operator calls `From::from` +// on the error value to convert it to a boxed trait object, a Box<error::Error>, +// which is polymorphic-- that means that lots of different kinds of errors +// can be returned from the same function because all errors act the same +// since they all implement the `error::Error` trait. +// Check out this section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator + +// Another another hint: Note that because the `?` operator returns +// the *unwrapped* value in the `Ok` case, if we want to return a `Result` from +// `read_and_validate` for *its* success case, we'll have to rewrap a value +// that we got from the return value of a `?`ed call in an `Ok`-- this will +// look like `Ok(something)`. + +// Another another another hint: `Result`s must be "used", that is, you'll +// get a warning if you don't handle a `Result` that you get in your +// function. Read more about that in the `std::result` module docs: +// https://doc.rust-lang.org/std/result/#results-must-be-used diff --git a/exercises/error_handling/option1.rs b/exercises/error_handling/option1.rs new file mode 100755 index 0000000..9cf0bc9 --- /dev/null +++ b/exercises/error_handling/option1.rs @@ -0,0 +1,45 @@ +// option1.rs +// This example panics because the second time it calls `pop`, the `vec` +// is empty, so `pop` returns `None`, and `unwrap` panics if it's called +// on `None`. Handle this in a more graceful way than calling `unwrap`! +// Scroll down for hints :) + +fn main() { + let mut list = vec![3]; + + let last = list.pop().unwrap(); + println!("The last item in the list is {:?}", last); + + let second_to_last = list.pop().unwrap(); + println!("The second-to-last item in the list is {:?}", second_to_last); +} + + + + + + + + + + + + + + + + + + + + + + + + + +// Try using a `match` statement where the arms are `Some(thing)` and `None`. +// Or set a default value to print out if you get `None` by using the +// function `unwrap_or`. +// Or use an `if let` statement on the result of `pop()` to both destructure +// a `Some` value and only print out something if we have a value! diff --git a/exercises/error_handling/result1.rs b/exercises/error_handling/result1.rs new file mode 100755 index 0000000..851ab45 --- /dev/null +++ b/exercises/error_handling/result1.rs @@ -0,0 +1,43 @@ +// result1.rs +// Make this test pass! Scroll down for hints :) + +#[derive(PartialEq,Debug)] +struct PositiveNonzeroInteger(u64); + +#[derive(PartialEq,Debug)] +enum CreationError { + Negative, + Zero, +} + +impl PositiveNonzeroInteger { + fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { + Ok(PositiveNonzeroInteger(value as u64)) + } +} + +#[test] +fn test_creation() { + assert!(PositiveNonzeroInteger::new(10).is_ok()); + assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10)); + assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); +} + + + + + + + + + + + + + + + + +// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. +// It should be doing some checking, returning an `Err` result if those checks fail, and only +// returning an `Ok` result if those checks determine that everything is... okay :) diff --git a/exercises/ex1.rs b/exercises/ex1.rs new file mode 100755 index 0000000..dc5f9ca --- /dev/null +++ b/exercises/ex1.rs @@ -0,0 +1,6 @@ +// ex1.rs +// Make me compile! :) + +fn main() { + println(); +} diff --git a/exercises/ex2.rs b/exercises/ex2.rs new file mode 100755 index 0000000..0fd714d --- /dev/null +++ b/exercises/ex2.rs @@ -0,0 +1,10 @@ +// ex2.rs +// Make me compile! + +fn something() -> String { + "hi!" +} + +fn main() { + println!("{}", something()); +} diff --git a/exercises/ex3.rs b/exercises/ex3.rs new file mode 100755 index 0000000..db27ad2 --- /dev/null +++ b/exercises/ex3.rs @@ -0,0 +1,10 @@ +// ex3.rs +// Make me compile! + +struct Foo { + capacity: i32, +} + +fn main() { + println!("{:?}", Foo { capacity: 3 }); +} diff --git a/exercises/ex4.rs b/exercises/ex4.rs new file mode 100755 index 0000000..362a557 --- /dev/null +++ b/exercises/ex4.rs @@ -0,0 +1,14 @@ +// ex4.rs +// Make me compile! + +fn something() -> Result<i32, std::num::ParseIntError> { + let x:i32 = "3".parse(); + Ok(x * 4) +} + +fn main() { + match something() { + Ok(..) => println!("You win!"), + Err(e) => println!("Oh no something went wrong: {}", e), + } +} diff --git a/exercises/ex5.rs b/exercises/ex5.rs new file mode 100755 index 0000000..2eb8cfd --- /dev/null +++ b/exercises/ex5.rs @@ -0,0 +1,22 @@ +// ex5.rs +// Make me compile! + +enum Reaction<'a> { + Sad(&'a str), + Happy(&'a str), +} + +fn express(sentiment: Reaction) { + match sentiment { + Reaction::Sad(s) => println!(":( {}", s), + Reaction::Happy(s) => println!(":) {}", s), + } +} + +fn main () { + let x = Reaction::Happy("It's a great day for Rust!"); + express(x); + express(x); + let y = Reaction::Sad("This code doesn't compile yet."); + express(y); +} diff --git a/exercises/functions/functions1.rs b/exercises/functions/functions1.rs new file mode 100755 index 0000000..396dd56 --- /dev/null +++ b/exercises/functions/functions1.rs @@ -0,0 +1,44 @@ +// functions1.rs +// Make me compile! Scroll down for hints :) + +fn main() { + call_me(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// This main function is calling a function that it expects to exist, but the +// function doesn't exist. It expects this function to have the name `call_me`. +// It expects this function to not take any arguments and not return a value. +// Sounds a lot like `main`, doesn't it? diff --git a/exercises/functions/functions2.rs b/exercises/functions/functions2.rs new file mode 100755 index 0000000..1cf95c3 --- /dev/null +++ b/exercises/functions/functions2.rs @@ -0,0 +1,42 @@ +// functions2.rs +// Make me compile! Scroll down for hints :) + +fn main() { + call_me(3); +} + +fn call_me(num) { + for i in 0..num { + println!("Ring! Call number {}", i + 1); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Rust requires that all parts of a function's signature have type annotations, +// but `call_me` is missing the type annotation of `num`. diff --git a/exercises/functions/functions3.rs b/exercises/functions/functions3.rs new file mode 100755 index 0000000..b17543b --- /dev/null +++ b/exercises/functions/functions3.rs @@ -0,0 +1,42 @@ +// functions3.rs +// Make me compile! Scroll down for hints :) + +fn main() { + call_me(); +} + +fn call_me(num: i32) { + for i in 0..num { + println!("Ring! Call number {}", i + 1); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// This time, the function *declaration* is okay, but there's something wrong +// with the place where we're calling the function. diff --git a/exercises/functions/functions4.rs b/exercises/functions/functions4.rs new file mode 100755 index 0000000..5baca0e --- /dev/null +++ b/exercises/functions/functions4.rs @@ -0,0 +1,44 @@ +// functions4.rs +// Make me compile! Scroll down for hints :) + +// This store is having a sale where if the price is an even number, you get +// 10 (money unit) off, but if it's an odd number, it's 3 (money unit) less. + +fn main() { + let original_price = 51; + println!("Your sale price is {}", sale_price(original_price)); +} + +fn sale_price(price: i32) -> { + if is_even(price) { + price - 10 + } else { + price - 3 + } +} + +fn is_even(num: i32) -> bool { + num % 2 == 0 +} + + + + + + + + + + + + + + + + + + + +// The error message points to line 12 and says it expects a type after the +// `->`. This is where the function's return type should be-- take a look at +// the `is_even` function for an example! diff --git a/exercises/functions/functions5.rs b/exercises/functions/functions5.rs new file mode 100755 index 0000000..d3ff002 --- /dev/null +++ b/exercises/functions/functions5.rs @@ -0,0 +1,47 @@ +// functions5.rs +// Make me compile! Scroll down for hints :) + +fn main() { + let answer = square(3); + println!("The answer is {}", answer); +} + +fn square(num: i32) -> i32 { + num * num; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// This is a really common error that can be fixed by removing one character. +// It happens because Rust distinguishes between expressions and statements: expressions return +// a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language. +// We want to return a value of `i32` type from the `square` function, but it is returning a `()` type... +// They are not the same. There are two solutions: +// 1. Add a `return` ahead of `num * num;` +// 2. remove `;`, make it to be `num * num` diff --git a/exercises/if/if1.rs b/exercises/if/if1.rs new file mode 100755 index 0000000..5118657 --- /dev/null +++ b/exercises/if/if1.rs @@ -0,0 +1,58 @@ +// if1.rs + +pub fn bigger(a: i32, b:i32) -> i32 { + // Complete this function to return the bigger number! + // Do not use: + // - return + // - another function call + // - additional variables + // Scroll down for hints. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ten_is_bigger_than_eight() { + assert_eq!(10, bigger(10, 8)); + } + + #[test] + fn fortytwo_is_bigger_than_thirtytwo() { + assert_eq!(42, bigger(32, 42)); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + +// It's possible to do this in one line if you would like! +// Some similar examples from other languages: +// - In C(++) this would be: `a > b ? a : b` +// - In Python this would be: `a if a > b else b` +// Remember in Rust that: +// - the `if` condition does not need to be surrounded by parentheses +// - `if`/`else` conditionals are expressions +// - Each condition is followed by a `{}` block. diff --git a/exercises/macros/macros1.rs b/exercises/macros/macros1.rs new file mode 100755 index 0000000..a7c78a5 --- /dev/null +++ b/exercises/macros/macros1.rs @@ -0,0 +1,64 @@ +// macros1.rs +// Make me compile! Scroll down for hints :) + +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; +} + +fn main() { + my_macro(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// When you call a macro, you need to add something special compared to a +// regular function call. If you're stuck, take a look at what's inside +// `my_macro`. diff --git a/exercises/macros/macros2.rs b/exercises/macros/macros2.rs new file mode 100755 index 0000000..bc2e56b --- /dev/null +++ b/exercises/macros/macros2.rs @@ -0,0 +1,73 @@ +// macros2.rs +// Make me compile! Scroll down for hints :) + +fn main() { + my_macro!(); +} + +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Macros don't quite play by the same rules as the rest of Rust, in terms of +// what's available where. + + + + + + + + +// Unlike other things in Rust, the order of "where you define a macro" versus +// "where you use it" actually matters. diff --git a/exercises/macros/macros3.rs b/exercises/macros/macros3.rs new file mode 100755 index 0000000..84c4308 --- /dev/null +++ b/exercises/macros/macros3.rs @@ -0,0 +1,75 @@ +// macros3.rs +// Make me compile, without taking the macro out of the module! Scroll down for hints :) + +mod macros { + macro_rules! my_macro { + () => { + println!("Check out my macro!"); + }; + } +} + +fn main() { + my_macro!(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// In order to use a macro outside of its module, you need to do something +// special to the module to lift the macro out into its parent. + + + + + + + + +// The same trick also works on "extern crate" statements for crates that have +// exported macros, if you've seen any of those around. diff --git a/exercises/macros/macros4.rs b/exercises/macros/macros4.rs new file mode 100755 index 0000000..d844bb0 --- /dev/null +++ b/exercises/macros/macros4.rs @@ -0,0 +1,77 @@ +// macros4.rs +// Make me compile! Scroll down for hints :) + +macro_rules! my_macro { + () => { + println!("Check out my macro!"); + } + ($val:expr) => { + println!("Look at this other macro: {}", $val); + } +} + +fn main() { + my_macro!(); + my_macro!(7777); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// You only need to add a single character to make this compile. + + + + + + + + + +// The way macros are written, it wants to see something between each +// "macro arm", so it can separate them. diff --git a/exercises/modules/modules1.rs b/exercises/modules/modules1.rs new file mode 100755 index 0000000..0e092c5 --- /dev/null +++ b/exercises/modules/modules1.rs @@ -0,0 +1,43 @@ +// modules1.rs +// Make me compile! Scroll down for hints :) + +mod sausage_factory { + fn make_sausage() { + println!("sausage!"); + } +} + +fn main() { + sausage_factory::make_sausage(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// 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 +// needs to be public. diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs new file mode 100755 index 0000000..164dfb0 --- /dev/null +++ b/exercises/modules/modules2.rs @@ -0,0 +1,45 @@ +// modules2.rs +// Make me compile! Scroll down for hints :) + +mod us_presidential_frontrunners { + use self::democrats::HILLARY_CLINTON as democrat; + use self::republicans::DONALD_TRUMP as republican; + + mod democrats { + pub const HILLARY_CLINTON: &'static str = "Hillary Clinton"; + pub const BERNIE_SANDERS: &'static str = "Bernie Sanders"; + } + + mod republicans { + pub const DONALD_TRUMP: &'static str = "Donald Trump"; + pub const JEB_BUSH: &'static str = "Jeb Bush"; + } +} + +fn main() { + println!("candidates: {} and {}", + us_presidential_frontrunners::democrat, + us_presidential_frontrunners::republican); +} + + + + + + + + + + + + + + + + + +// The us_presidential_frontrunners module is trying to present an external +// interface (the `democrat` and `republican` constants) that is different than +// its internal structure (the `democrats` and `republicans` modules and +// associated constants). It's almost there except for one keyword missing for +// each constant. diff --git a/exercises/move_semantics/move_semantics1.rs b/exercises/move_semantics/move_semantics1.rs new file mode 100755 index 0000000..37038ec --- /dev/null +++ b/exercises/move_semantics/move_semantics1.rs @@ -0,0 +1,43 @@ +// move_semantics1.rs +// Make me compile! Scroll down for hints :) + +fn main() { + let vec0 = Vec::new(); + + let vec1 = fill_vec(vec0); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + + vec1.push(88); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + +} + +fn fill_vec(vec: Vec<i32>) -> Vec<i32> { + let mut vec = vec; + + vec.push(22); + vec.push(44); + vec.push(66); + + vec +} + + + + + + + + + + + + + + + +// So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11, +// right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11 +// where the error is. diff --git a/exercises/move_semantics/move_semantics2.rs b/exercises/move_semantics/move_semantics2.rs new file mode 100755 index 0000000..b50e349 --- /dev/null +++ b/exercises/move_semantics/move_semantics2.rs @@ -0,0 +1,54 @@ +// move_semantics2.rs +// Make me compile without changing line 10! Scroll down for hints :) + +fn main() { + let vec0 = Vec::new(); + + let mut vec1 = fill_vec(vec0); + + // Do not change the following line! + println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); + + vec1.push(88); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + +} + +fn fill_vec(vec: Vec<i32>) -> Vec<i32> { + let mut vec = vec; + + vec.push(22); + vec.push(44); + vec.push(66); + + vec +} + + + + + + + + + + + + + + +// So `vec0` is being *moved* into the function `fill_vec` when we call it on +// line 7, which means it gets dropped at the end of `fill_vec`, which means we +// can't use `vec0` again on line 10 (or anywhere else in `main` after the +// `fill_vec` call for that matter). We could fix this in a few ways, try them +// all! +// 1. Make another, separate version of the data that's in `vec0` and pass that +// to `fill_vec` instead. +// 2. Make `fill_vec` borrow its argument instead of taking ownership of it, +// and then copy the data within the function in order to return an owned +// `Vec<i32>` +// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be +// mutable), modify it directly, then not return anything. Then you can get rid +// of `vec1` entirely -- note that this will change what gets printed by the +// first `println!` diff --git a/exercises/move_semantics/move_semantics3.rs b/exercises/move_semantics/move_semantics3.rs new file mode 100755 index 0000000..8e7b0ad --- /dev/null +++ b/exercises/move_semantics/move_semantics3.rs @@ -0,0 +1,46 @@ +// move_semantics3.rs +// Make me compile without adding new lines-- just changing existing lines! +// (no lines with multiple semicolons necessary!) +// Scroll down for hints :) + +fn main() { + let vec0 = Vec::new(); + + let mut vec1 = fill_vec(vec0); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + + vec1.push(88); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + +} + +fn fill_vec(vec: Vec<i32>) -> Vec<i32> { + vec.push(22); + vec.push(44); + vec.push(66); + + vec +} + + + + + + + + + + + + + + + + + +// The difference between this one and the previous ones is that the first line +// of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can, +// instead of adding that line back, add `mut` in one place that will change +// an existing binding to be a mutable binding instead of an immutable one :) diff --git a/exercises/move_semantics/move_semantics4.rs b/exercises/move_semantics/move_semantics4.rs new file mode 100755 index 0000000..903a330 --- /dev/null +++ b/exercises/move_semantics/move_semantics4.rs @@ -0,0 +1,48 @@ +// move_semantics4.rs +// Refactor this code so that instead of having `vec0` and creating the vector +// in `fn main`, we instead create it within `fn fill_vec` and transfer the +// freshly created vector from fill_vec to its caller. Scroll for hints! + +fn main() { + let vec0 = Vec::new(); + + let mut vec1 = fill_vec(vec0); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + + vec1.push(88); + + println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); + +} + +fn fill_vec(vec: Vec<i32>) -> Vec<i32> { + let mut vec = vec; + + vec.push(22); + vec.push(44); + vec.push(66); + + vec +} + + + + + + + + + + + + +// Stop reading whenever you feel like you have enough direction :) Or try +// doing one step and then fixing the compiler errors that result! +// So the end goal is to: +// - get rid of the first line in main that creates the new vector +// - so then `vec0` doesn't exist, so we can't pass it to `fill_vec` +// - we don't want to pass anything to `fill_vec`, so its signature should +// reflect that it does not take any arguments +// - since we're not creating a new vec in `main` anymore, we need to create +// a new vec in `fill_vec`, similarly to the way we did in `main` diff --git a/exercises/primitive_types/primitive_types1.rs b/exercises/primitive_types/primitive_types1.rs new file mode 100755 index 0000000..c3d11fe --- /dev/null +++ b/exercises/primitive_types/primitive_types1.rs @@ -0,0 +1,17 @@ +// primitive_types1.rs +// Fill in the rest of the line that has code missing! +// No hints, there's no tricks, just get used to typing these :) + +fn main() { + // Booleans (`bool`) + + let is_morning = true; + if is_morning { + println!("Good morning!"); + } + + let // Finish the rest of this line like the example! Or make it be false! + if is_evening { + println!("Good evening!"); + } +} diff --git a/exercises/primitive_types/primitive_types2.rs b/exercises/primitive_types/primitive_types2.rs new file mode 100755 index 0000000..f5c8f87 --- /dev/null +++ b/exercises/primitive_types/primitive_types2.rs @@ -0,0 +1,27 @@ +// primitive_types2.rs +// Fill in the rest of the line that has code missing! +// No hints, there's no tricks, just get used to typing these :) + +fn main() { + // Characters (`char`) + + let my_first_initial = 'C'; + if my_first_initial.is_alphabetic() { + println!("Alphabetical!"); + } else if my_first_initial.is_numeric() { + println!("Numerical!"); + } else { + println!("Neither alphabetic nor numeric!"); + } + + let // Finish this line like the example! What's your favorite character? + // Try a letter, try a number, try a special character, try a character + // from a different language than your own, try an emoji! + if your_character.is_alphabetic() { + println!("Alphabetical!"); + } else if your_character.is_numeric() { + println!("Numerical!"); + } else { + println!("Neither alphabetic nor numeric!"); + } +} diff --git a/exercises/primitive_types/primitive_types3.rs b/exercises/primitive_types/primitive_types3.rs new file mode 100755 index 0000000..7ce2226 --- /dev/null +++ b/exercises/primitive_types/primitive_types3.rs @@ -0,0 +1,47 @@ +// primitive_types3.rs +// Create an array with at least 100 elements in it where the ??? is. +// Scroll down for hints! + +fn main() { + let a = ??? + + if a.len() >= 100 { + println!("Wow, that's a big array!"); + } else { + println!("Meh, I eat arrays like that for breakfast."); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + +// There's a shorthand to initialize Arrays with a certain size that does not +// require you to type in 100 items (but you certainly can if you want!). +// For example, you can do: +// let array = ["Are we there yet?"; 10]; + +// Bonus: what are some other things you could have that would return true +// for `a.len() >= 100`? diff --git a/exercises/primitive_types/primitive_types4.rs b/exercises/primitive_types/primitive_types4.rs new file mode 100755 index 0000000..7dc9e47 --- /dev/null +++ b/exercises/primitive_types/primitive_types4.rs @@ -0,0 +1,49 @@ +// primitive_types4.rs +// Get a slice out of Array a where the ??? is so that the `if` statement +// returns true. Scroll down for hints!! + +fn main() { + let a = [1, 2, 3, 4, 5]; + + let nice_slice = ??? + + if nice_slice == [2, 3, 4] { + println!("Nice slice!"); + } else { + println!("Not quite what I was expecting... I see: {:?}", nice_slice); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + +// Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch04-03-slices.html#other-slices +// and use the starting and ending indices of the items in the Array +// that you want to end up in the slice. + +// If you're curious why the right hand of the `==` comparison does not +// have an ampersand for a reference since the left hand side is a +// reference, take a look at the Deref coercions section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods diff --git a/exercises/primitive_types/primitive_types5.rs b/exercises/primitive_types/primitive_types5.rs new file mode 100755 index 0000000..4045e78 --- /dev/null +++ b/exercises/primitive_types/primitive_types5.rs @@ -0,0 +1,45 @@ +// primitive_types5.rs +// Destructure the `cat` tuple so that the println will work. +// Scroll down for hints! + +fn main() { + let cat = ("Furry McFurson", 3.5); + let /* your pattern here */ = cat; + + println!("{} is {} years old.", name, age); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Take a look at the Data Types -> The Tuple Type section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch03-02-data-types.html#the-tuple-type +// Particularly the part about destructuring (second to last example in the section). +// You'll need to make a pattern to bind `name` and `age` to the appropriate parts +// of the tuple. You can do it!! diff --git a/exercises/primitive_types/primitive_types6.rs b/exercises/primitive_types/primitive_types6.rs new file mode 100755 index 0000000..439a56b --- /dev/null +++ b/exercises/primitive_types/primitive_types6.rs @@ -0,0 +1,45 @@ +// primitive_types6.rs +// Use a tuple index to access the second element of `numbers`. +// You can put this right into the `println!` where the ??? is. +// Scroll down for hints! + +fn main() { + let numbers = (1, 2, 3); + println!("The second number is {}", ???); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// While you could use a destructuring `let` for the tuple here, try +// indexing into it instead, as explained in the last example of the +// Data Types -> The Tuple Type section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch03-02-data-types.html#the-tuple-type +// Now you have another tool in your toolbox! diff --git a/exercises/standard_library_types/arc1.rs b/exercises/standard_library_types/arc1.rs new file mode 100755 index 0000000..c744a10 --- /dev/null +++ b/exercises/standard_library_types/arc1.rs @@ -0,0 +1,56 @@ +// arc1.rs +// Make this code compile by filling in a value for `shared_numbers` where the +// TODO comment is and creating an initial binding for `child_numbers` +// somewhere. Try not to create any copies of the `numbers` Vec! +// Scroll down for hints :) + +use std::sync::Arc; +use std::thread; + +fn main() { + let numbers: Vec<_> = (0..100u32).collect(); + let shared_numbers = // TODO + let mut joinhandles = Vec::new(); + + for offset in 0..8 { + joinhandles.push( + thread::spawn(move || { + let mut i = offset; + let mut sum = 0; + while i < child_numbers.len() { + sum += child_numbers[i]; + i += 5; + } + println!("Sum of offset {} is {}", offset, sum); + })); + } + for handle in joinhandles.into_iter() { + handle.join().unwrap(); + } +} + + + + + + + + + + + + + + + + + + + + +// Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order +// to avoid creating a copy of `numbers`, you'll need to create `child_numbers` +// inside the loop but still in the main thread. + +// `child_numbers` should be a clone of the Arc of the numbers instead of a +// thread-local copy of the numbers. diff --git a/exercises/standard_library_types/iterator3.rs b/exercises/standard_library_types/iterator3.rs new file mode 100755 index 0000000..1d2e135 --- /dev/null +++ b/exercises/standard_library_types/iterator3.rs @@ -0,0 +1,147 @@ +// iterator3.rs +// This is a bigger exercise than most of the others! You can do it! +// Here is your mission, should you choose to accept it: +// 1. Complete the divide function to get the first four tests to pass +// 2. Uncomment the last two tests and get them to pass by filling in +// values for `x` using `division_results`. +// Scroll down for a minor hint for part 2, and scroll down further for +// a major hint. +// Have fun :-) + +#[derive(Debug, PartialEq, Eq)] +pub enum DivisionError { + NotDivisible(NotDivisibleError), + DivideByZero, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct NotDivisibleError { + dividend: i32, + divisor: i32, +} + +// This function should calculate `a` divided by `b` if `a` is +// evenly divisible by b. +// Otherwise, it should return a suitable error. +pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> { +} + +#[cfg(test)] +mod tests { + use super::*; + + // Tests that verify your `divide` function implementation + #[test] + fn test_success() { + assert_eq!(divide(81, 9), Ok(9)); + } + + #[test] + fn test_not_divisible() { + assert_eq!( + divide(81, 6), + Err(DivisionError::NotDivisible(NotDivisibleError{ + dividend: 81, + divisor: 6 + })) + ); + } + + #[test] + fn test_divide_by_0() { + assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); + } + + #[test] + fn test_divide_0_by_something() { + assert_eq!(divide(0, 81), Ok(0)); + } + + // Iterator exercises using your `divide` function + /* + #[test] + fn result_with_list() { + let numbers = vec![27, 297, 38502, 81]; + let division_results = numbers.into_iter().map(|n| divide(n, 27)); + let x //... Fill in here! + assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])"); + } + + #[test] + fn list_of_results() { + let numbers = vec![27, 297, 38502, 81]; + let division_results = numbers.into_iter().map(|n| divide(n, 27)); + let x //... Fill in here! + assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]"); + } + */ +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Minor hint: In each of the two cases in the match in main, you can create x with either +// a 'turbofish' or by hinting the type of x to the compiler. You may try both. + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Major hint: Have a look at the Iter trait and at the explanation of its collect function. +// Especially the part about Result is interesting. diff --git a/exercises/standard_library_types/iterators4.rs b/exercises/standard_library_types/iterators4.rs new file mode 100755 index 0000000..13613a6 --- /dev/null +++ b/exercises/standard_library_types/iterators4.rs @@ -0,0 +1,61 @@ +// iterators4.rs + +pub fn factorial(num: u64) -> u64 { + // Complete this function to return factorial of num + // Do not use: + // - return + // For extra fun don't use: + // - imperative style loops (for, while) + // - additional variables + // For the most fun don't use: + // - recursion + // Scroll down for hints. +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn factorial_of_1() { + assert_eq!(1, factorial(1)); + } + #[test] + fn factorial_of_2() { + assert_eq!(2, factorial(2)); + } + + #[test] + fn factorial_of_4() { + assert_eq!(24, factorial(4)); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + +// In an imperative language you might write a for loop to iterate through +// multiply the values into a mutable variable. Or you might write code more +// functionally with recursion and a match clause. But you can also use ranges +// and iterators to solve this in rust. diff --git a/exercises/strings/strings1.rs b/exercises/strings/strings1.rs new file mode 100755 index 0000000..2e5088f --- /dev/null +++ b/exercises/strings/strings1.rs @@ -0,0 +1,46 @@ +// strings1.rs +// Make me compile without changing the function signature! Scroll down for hints :) + +fn main() { + let answer = current_favorite_color(); + println!("My current favorite color is {}", answer); +} + +fn current_favorite_color() -> String { + "blue" +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// The `current_favorite_color` function is currently returning a string slice with the `'static` +// lifetime. We know this because the data of the string lives in our code itself -- it doesn't +// come from a file or user input or another program -- so it will live as long as our program +// lives. But it is still a string slice. There's one way to create a `String` by converting a +// string slice covered in the Strings chapter of the book, and another way that uses the `From` +// trait. diff --git a/exercises/strings/strings2.rs b/exercises/strings/strings2.rs new file mode 100755 index 0000000..c77e16f --- /dev/null +++ b/exercises/strings/strings2.rs @@ -0,0 +1,44 @@ +// strings2.rs +// Make me compile without changing the function signature! Scroll down for hints :) + +fn main() { + let word = String::from("green"); // Try not changing this line :) + if is_a_color_word(word) { + println!("That is a color word I know!"); + } else { + println!("That is not a color word I know."); + } +} + +fn is_a_color_word(attempt: &str) -> bool { + attempt == "green" || attempt == "blue" || attempt == "red" +} + + + + + + + + + + + + + + + + + + + + + + + + + + +// 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 to add one character to line +// 6, though, that will coerce the `String` into a string slice. diff --git a/exercises/strings/strings3.rs b/exercises/strings/strings3.rs new file mode 100755 index 0000000..b6f6a1e --- /dev/null +++ b/exercises/strings/strings3.rs @@ -0,0 +1,21 @@ +// strings3.rs +// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your +// task is to call one of these two functions on each value depending on what +// 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) { println!("{}", arg); } +fn string(arg: String) { println!("{}", arg); } + +fn main() { + ("blue"); + ("red".to_string()); + (String::from("hi")); + ("rust is fun!".to_owned()); + ("nice weather".into()); + (format!("Interpolation {}", "Station")); + (&String::from("abc")[0..1]); + (" hello there ".trim()); + ("Happy Monday!".to_string().replace("Mon", "Tues")); + ("mY sHiFt KeY iS sTiCkY".to_lowercase()); +} diff --git a/exercises/tests/tests1.rs b/exercises/tests/tests1.rs new file mode 100755 index 0000000..959ed85 --- /dev/null +++ b/exercises/tests/tests1.rs @@ -0,0 +1,49 @@ +// tests1.rs +// Tests are important to ensure that your code does what you think it should do. +// Tests can be run on this file with the following command: +// rustc --test tests1.rs + +// This test has a problem with it -- make the test compile! Make the test +// pass! Make the test fail! Scroll down for hints :) + +#[cfg(test)] +mod tests { + #[test] + fn you_can_assert() { + assert!(); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// You don't even need to write any code to test -- you can just test values and run that, even +// though you wouldn't do that in real life :) `assert!` is a macro that needs an argument. +// Depending on the value of the argument, `assert!` will do nothing (in which case the test will +// pass) or `assert!` will panic (in which case the test will fail). So try giving different values +// to `assert!` and see which ones compile, which ones pass, and which ones fail :) diff --git a/exercises/tests/tests2.rs b/exercises/tests/tests2.rs new file mode 100755 index 0000000..6775d61 --- /dev/null +++ b/exercises/tests/tests2.rs @@ -0,0 +1,44 @@ +// tests2.rs +// This test has a problem with it -- make the test compile! Make the test +// pass! Make the test fail! Scroll down for hints :) + +#[cfg(test)] +mod tests { + #[test] + fn you_can_assert_eq() { + assert_eq!(); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Like the previous exercise, you don't need to write any code to get this test to compile and +// run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two +// values that are equal! Try giving it two arguments that are different! Try giving it two values +// that are of different types! Try switching which argument comes first and which comes second! diff --git a/exercises/tests/tests3.rs b/exercises/tests/tests3.rs new file mode 100755 index 0000000..e041f38 --- /dev/null +++ b/exercises/tests/tests3.rs @@ -0,0 +1,43 @@ +// tests3.rs +// This test isn't testing our function -- make it do that in such a way that +// the test passes. Then write a second test that tests that we get the result +// we expect to get when we call `is_even(5)`. Scroll down for hints! + +pub fn is_even(num: i32) -> bool { + num % 2 == 0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_true_when_even() { + assert!(false); + } +} + + + + + + + + + + + + + + + + + + + + + + +// You can call a function right where you're passing arguments to `assert!` -- so you could do +// something like `assert!(having_fun())`. If you want to check that you indeed get false, you +// can negate the result of what you're doing using `!`, like `assert!(!having_fun())`. diff --git a/exercises/tests/tests4.rs b/exercises/tests/tests4.rs new file mode 100755 index 0000000..23d444a --- /dev/null +++ b/exercises/tests/tests4.rs @@ -0,0 +1,19 @@ +// tests4.rs +// This test isn't testing our function -- make it do that in such a way that +// the test passes. Then write a second test that tests that we get the result +// we expect to get when we call `times_two` with a negative number. +// No hints, you can do this :) + +pub fn times_two(num: i32) -> i32 { + num * 2 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn returns_twice_of_positive_numbers() { + assert_eq!(4, 4); + } +} diff --git a/exercises/threads/threads1.rs b/exercises/threads/threads1.rs new file mode 100755 index 0000000..4f9aa89 --- /dev/null +++ b/exercises/threads/threads1.rs @@ -0,0 +1,95 @@ +// threads1.rs +// Make this compile! Scroll down for hints :) The idea is the thread +// spawned on line 19 is completing jobs while the main thread is +// monitoring progress until 10 jobs are completed. If you see 6 lines +// of "waiting..." and the program ends without timing out the playground, +// you've got it :) + +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +struct JobStatus { + jobs_completed: u32, +} + +fn main() { + let status = Arc::new(JobStatus { jobs_completed: 0 }); + let status_shared = status.clone(); + thread::spawn(move || { + for _ in 0..10 { + thread::sleep(Duration::from_millis(250)); + status_shared.jobs_completed += 1; + } + }); + while status.jobs_completed < 10 { + println!("waiting... "); + thread::sleep(Duration::from_millis(500)); + } +} + + + + + + + + + + + + + + +// `Arc` is an Atomic Reference Counted pointer that allows safe, shared access +// to **immutable** data. But we want to *change* the number of `jobs_completed` +// so we'll need to also use another type that will only allow one thread to +// mutate the data at a time. Take a look at this section of the book: +// https://doc.rust-lang.org/stable/book/second-edition/ch16-03-shared-state.html#atomic-reference-counting-with-arct +// and keep scrolling if you'd like more hints :) + + + + + + + + + + +// Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like: +// `let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));` +// Similar to the code in the example in the book that happens after the text +// that says "We can use Arc<T> to fix this.". If not, give that a try! If you +// do and would like more hints, keep scrolling!! + + + + + + + + + + + + +// Make sure neither of your threads are holding onto the lock of the mutex +// while they are sleeping, since this will prevent the other thread from +// being allowed to get the lock. Locks are automatically released when +// they go out of scope. + +// Ok, so, real talk, this was actually tricky for *me* to do too. And +// I could see a lot of different problems you might run into, so at this +// point I'm not sure which one you've hit :) Please see a few possible +// answers on https://github.com/carols10cents/rustlings/issues/3 -- +// mine is a little more complicated because I decided I wanted to see +// the number of jobs currently done when I was checking the status. + +// Please open an issue if you're still running into a problem that +// these hints are not helping you with, or if you've looked at the sample +// answers and don't understand why they work and yours doesn't. + +// If you've learned from the sample solutions, I encourage you to come +// back to this exercise and try it again in a few days to reinforce +// what you've learned :) diff --git a/exercises/variables/variables1.rs b/exercises/variables/variables1.rs new file mode 100755 index 0000000..1cdd270 --- /dev/null +++ b/exercises/variables/variables1.rs @@ -0,0 +1,42 @@ +// variables1.rs +// Make me compile! Scroll down for hints :) + +fn main() { + x = 5; + println!("x has the value {}", x); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Hint: The declaration on line 5 is missing a keyword that is needed in Rust +// to create a new variable binding. diff --git a/exercises/variables/variables2.rs b/exercises/variables/variables2.rs new file mode 100755 index 0000000..a0b4a37 --- /dev/null +++ b/exercises/variables/variables2.rs @@ -0,0 +1,47 @@ +// variables2.rs +// Make me compile! Scroll down for hints :) + +fn main() { + let x; + if x == 10 { + println!("Ten!"); + } else { + println!("Not ten!"); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// The compiler message is saying that Rust cannot infer the type that the +// variable binding `x` has with what is given here. +// What happens if you annotate line 5 with a type annotation? +// What if you give x a value? +// What if you do both? +// What type should x be, anyway? +// What if x is the same type as 10? What if it's a different type? diff --git a/exercises/variables/variables3.rs b/exercises/variables/variables3.rs new file mode 100755 index 0000000..165a277 --- /dev/null +++ b/exercises/variables/variables3.rs @@ -0,0 +1,43 @@ +// variables3.rs +// Make me compile! Scroll down for hints :) + +fn main() { + let x = 3; + println!("Number {}", x); + x = 5; + println!("Number {}", x); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// In Rust, variable bindings are immutable by default. But here we're trying +// to reassign a different value to x! There's a keyword we can use to make +// a variable binding mutable instead. diff --git a/exercises/variables/variables4.rs b/exercises/variables/variables4.rs new file mode 100755 index 0000000..71ebf0f --- /dev/null +++ b/exercises/variables/variables4.rs @@ -0,0 +1,45 @@ +// variables4.rs +// Make me compile! Scroll down for hints :) + +fn main() { + let x: i32; + println!("Number {}", x); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// Oops! In this exercise, we have a variable binding that we've created on +// line 5, and we're trying to use it on line 6, but we haven't given it a +// value. We can't print out something that isn't there; try giving x a value! +// This is an error that can cause bugs that's very easy to make in any +// programming language -- thankfully the Rust compiler has caught this for us! |
