mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba087ce64a | ||
|
|
3b03865a62 | ||
|
|
33fa274bbf | ||
|
|
23f700dc23 | ||
|
|
d876649616 | ||
|
|
e4c14ac76e | ||
|
|
b438049c39 | ||
|
|
b017579577 | ||
|
|
c8e4b357a3 | ||
|
|
8774e47dc3 | ||
|
|
e422ab1507 | ||
|
|
cdd8e19716 | ||
|
|
91d86a1de9 | ||
|
|
6a10f900b4 | ||
|
|
9b9a89c79a | ||
|
|
123e6426d1 | ||
|
|
427ec6b2e4 | ||
|
|
03dcb582e6 | ||
|
|
1043a06124 | ||
|
|
d20e413a68 | ||
|
|
9bf4c5e8df | ||
|
|
633303d4b8 | ||
|
|
a4a1098766 | ||
|
|
0bd459dcac | ||
|
|
3b4514b686 | ||
|
|
2e05606edc | ||
|
|
c8c1b87a01 | ||
|
|
34ea029df8 | ||
|
|
3a4433d5a2 | ||
|
|
de6c45ad24 | ||
|
|
fadade8592 | ||
|
|
d91044f3a2 | ||
|
|
a3ea37b76e | ||
|
|
ec63cadadb | ||
|
|
84d8305730 | ||
|
|
73777980f1 | ||
|
|
75788b1148 | ||
|
|
dd9b2ddc89 | ||
|
|
b7ddd09fab | ||
|
|
48ffcbd2c4 | ||
|
|
68d3ac567c | ||
|
|
50ab289da6 | ||
|
|
4e079fdd08 | ||
|
|
91fc9e3118 | ||
|
|
a2f0401c4c | ||
|
|
1b85828548 | ||
|
|
4c46e5e1a3 | ||
|
|
4da9e7ee29 | ||
|
|
72e615aa7a | ||
|
|
cd02abc481 | ||
|
|
399ab328d8 | ||
|
|
809ec2ce01 | ||
|
|
11d2cf0d60 | ||
|
|
dbb2624403 | ||
|
|
4d4fa77459 | ||
|
|
3145794084 | ||
|
|
d9b69bd1a0 | ||
|
|
7cd635fa84 | ||
|
|
ce40e201f0 | ||
|
|
404f3ef465 | ||
|
|
e1be594fdd | ||
|
|
9569c9a9e7 | ||
|
|
91530f5716 | ||
|
|
650b1dee54 | ||
|
|
6b6dc9dd48 | ||
|
|
3a9ec4192d | ||
|
|
4f7dbbd2c3 | ||
|
|
8c37db1a23 | ||
|
|
c6b7ad8878 | ||
|
|
aa9a943ddf |
@@ -838,6 +838,97 @@
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "stoiandan",
|
||||
"name": "Stoian Dan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10388612?v=4",
|
||||
"profile": "https://github.com/stoiandan",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "PiDelport",
|
||||
"name": "Pi Delport",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/630271?v=4",
|
||||
"profile": "https://about.me/pjdelport",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sateeshkumarb",
|
||||
"name": "Sateesh ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/429263?v=4",
|
||||
"profile": "https://github.com/sateeshkumarb",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kayuapi",
|
||||
"name": "ZC",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10304328?v=4",
|
||||
"profile": "https://github.com/kayuapi",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hyperparabolic",
|
||||
"name": "hyperparabolic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12348474?v=4",
|
||||
"profile": "https://github.com/hyperparabolic",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kolbma",
|
||||
"name": "arlecchino",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5228369?v=4",
|
||||
"profile": "https://www.net4visions.at",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jazzplato",
|
||||
"name": "Richthofen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7576730?v=4",
|
||||
"profile": "https://richthofen.io/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cseltol",
|
||||
"name": "Ivan Nerazumov",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/64264529?v=4",
|
||||
"profile": "https://github.com/cseltol",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lauralindzey",
|
||||
"name": "lauralindzey",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/65185744?v=4",
|
||||
"profile": "https://github.com/lauralindzey",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sinharaksh1t",
|
||||
"name": "Rakshit Sinha",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/28585848?v=4",
|
||||
"profile": "https://github.com/sinharaksh1t",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 8,
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,3 +1,27 @@
|
||||
<a name="4.5.0"></a>
|
||||
## 4.5.0 (2021-07-07)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Add move_semantics5 exercise. (#746) ([399ab328](https://github.com/rust-lang/rustlings/commit/399ab328d8d407265c09563aa4ef4534b2503ff2))
|
||||
* **cli:** Add "next" to run the next unsolved exercise. (#785) ([d20e413a](https://github.com/rust-lang/rustlings/commit/d20e413a68772cd493561f2651cf244e822b7ca5))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* rename result1 to errors4 ([50ab289d](https://github.com/rust-lang/rustlings/commit/50ab289da6b9eb19a7486c341b00048c516b88c0))
|
||||
* move_semantics5 hints ([1b858285](https://github.com/rust-lang/rustlings/commit/1b85828548f46f58b622b5e0c00f8c989f928807))
|
||||
* remove trailing whitespaces from iterators1 ([4d4fa774](https://github.com/rust-lang/rustlings/commit/4d4fa77459392acd3581c6068aa8be9a02de12fc))
|
||||
* add hints to generics1 and generics2 exercises ([31457940](https://github.com/rust-lang/rustlings/commit/31457940846b3844d78d4a4d2b074bc8d6aaf1eb))
|
||||
* remove trailing whitespace ([d9b69bd1](https://github.com/rust-lang/rustlings/commit/d9b69bd1a0a7a99f2c0d80933ad2eea44c8c71b2))
|
||||
* **installation:** first PowerShell command ([aa9a943d](https://github.com/rust-lang/rustlings/commit/aa9a943ddf3ae260782e73c26bcc9db60e5894b6))
|
||||
* **iterators5:** derive Clone, Copy ([91fc9e31](https://github.com/rust-lang/rustlings/commit/91fc9e3118f4af603c9911698cc2a234725cb032))
|
||||
* **quiz1:** Updated question description (#794) ([d8766496](https://github.com/rust-lang/rustlings/commit/d876649616cc8a8dd5f539f8bc1a5434b960b1e9))
|
||||
* **try_from_into, from_str:** hints for dyn Error ([11d2cf0d](https://github.com/rust-lang/rustlings/commit/11d2cf0d604dee3f5023c17802d69438e69fa50e))
|
||||
* **variables5:** confine the answer further ([48ffcbd2](https://github.com/rust-lang/rustlings/commit/48ffcbd2c4cc4d936c2c7480019190f179813cc5))
|
||||
|
||||
|
||||
|
||||
<a name="4.4.0"></a>
|
||||
## 4.4.0 (2021-04-24)
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -539,7 +539,7 @@ checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
|
||||
[[package]]
|
||||
name = "rustlings"
|
||||
version = "4.4.0"
|
||||
version = "4.5.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"assert_cmd",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "4.4.0"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
version = "4.5.0"
|
||||
authors = ["anastasie <ana@ana.st>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
36
README.md
36
README.md
@@ -1,5 +1,5 @@
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# rustlings 🦀❤️
|
||||
@@ -33,10 +33,10 @@ This will install Rustlings and give you access to the `rustlings` command. Run
|
||||
|
||||
## Windows
|
||||
|
||||
In PowerShell, set `ExecutionPolicy` to `RemoteSigned`:
|
||||
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
|
||||
|
||||
```ps
|
||||
Set-ExecutionPolicy RemoteSigned
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
|
||||
Then, you can run:
|
||||
@@ -57,12 +57,12 @@ When you get a permission denied message then you have to exclude the directory
|
||||
|
||||
## Manually
|
||||
|
||||
Basically: Clone the repository, checkout to the latest tag, run `cargo install`.
|
||||
Basically: Clone the repository at the latest tag, run `cargo install`.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.5.0)
|
||||
git clone -b 4.5.0 --depth 1 https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/4.4.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
@@ -97,6 +97,12 @@ In case you want to go by your own order, or want to only verify a single exerci
|
||||
rustlings run myExercise1
|
||||
```
|
||||
|
||||
Or simply use the following command to run the next unsolved exercise in the course:
|
||||
|
||||
```bash
|
||||
rustlings run next
|
||||
```
|
||||
|
||||
In case you get stuck, you can run the following command to get a hint for your
|
||||
exercise:
|
||||
|
||||
@@ -104,6 +110,12 @@ exercise:
|
||||
rustlings hint myExercise1
|
||||
```
|
||||
|
||||
You can also get the hint for the next unsolved exercise with the following command:
|
||||
|
||||
``` bash
|
||||
rustlings hint next
|
||||
```
|
||||
|
||||
To check your progress, you can run the following command:
|
||||
```bash
|
||||
rustlings list
|
||||
@@ -278,6 +290,18 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hongshaoyang"><img src="https://avatars.githubusercontent.com/u/19281800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shao Yang Hong</b></sub></a><br /><a href="#content-hongshaoyang" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/bmacer"><img src="https://avatars.githubusercontent.com/u/13931806?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon Macer</b></sub></a><br /><a href="#content-bmacer" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/stoiandan"><img src="https://avatars.githubusercontent.com/u/10388612?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stoian Dan</b></sub></a><br /><a href="#content-stoiandan" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://about.me/pjdelport"><img src="https://avatars.githubusercontent.com/u/630271?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pi Delport</b></sub></a><br /><a href="#content-PiDelport" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/sateeshkumarb"><img src="https://avatars.githubusercontent.com/u/429263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sateesh </b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sateeshkumarb" title="Code">💻</a> <a href="#content-sateeshkumarb" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/kayuapi"><img src="https://avatars.githubusercontent.com/u/10304328?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZC</b></sub></a><br /><a href="#content-kayuapi" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/hyperparabolic"><img src="https://avatars.githubusercontent.com/u/12348474?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hyperparabolic</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hyperparabolic" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.net4visions.at"><img src="https://avatars.githubusercontent.com/u/5228369?v=4?s=100" width="100px;" alt=""/><br /><sub><b>arlecchino</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kolbma" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://richthofen.io/"><img src="https://avatars.githubusercontent.com/u/7576730?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richthofen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jazzplato" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/cseltol"><img src="https://avatars.githubusercontent.com/u/64264529?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Nerazumov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cseltol" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/lauralindzey"><img src="https://avatars.githubusercontent.com/u/65185744?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lauralindzey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lauralindzey" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/sinharaksh1t"><img src="https://avatars.githubusercontent.com/u/28585848?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakshit Sinha</b></sub></a><br /><a href="#content-sinharaksh1t" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
| structs | §5.1 |
|
||||
| enums | §6 |
|
||||
| modules | §7.2 |
|
||||
| collections | §8.1 |
|
||||
| collections | §8.1, §8.3 |
|
||||
| strings | §8.2 |
|
||||
| error_handling | §9 |
|
||||
| generics | §10 |
|
||||
|
||||
@@ -20,3 +20,4 @@ structures that are used very often in Rust programs:
|
||||
## Further information
|
||||
|
||||
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
|
||||
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// result1.rs
|
||||
// Make this test pass! Execute `rustlings hint result1` for hints :)
|
||||
// errors4.rs
|
||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
53
exercises/error_handling/errors5.rs
Normal file
53
exercises/error_handling/errors5.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// errors5.rs
|
||||
|
||||
// This program uses a completed version of the code from errors4.
|
||||
// It won't compile right now! Why?
|
||||
// Execute `rustlings hint errors5` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// TODO: update the return type of `main()` to make this compile.
|
||||
fn main() -> Result<(), ParseIntError> {
|
||||
let pretend_user_input = "42";
|
||||
let x: i64 = pretend_user_input.parse()?;
|
||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is required so that `CreationError` can implement `error::Error`.
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let description = match *self {
|
||||
CreationError::Negative => "number is negative",
|
||||
CreationError::Zero => "number is zero",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {}
|
||||
95
exercises/error_handling/errors6.rs
Normal file
95
exercises/error_handling/errors6.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
// errors6.rs
|
||||
|
||||
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
|
||||
// for library code, where callers might want to make decisions based on the
|
||||
// error content, instead of printing it out or propagating it further. Here,
|
||||
// we define a custom error type to make it possible for callers to decide
|
||||
// what to do next when our function returns an error.
|
||||
|
||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ParsePosNonzeroError {
|
||||
Creation(CreationError),
|
||||
ParseInt(ParseIntError)
|
||||
}
|
||||
|
||||
impl ParsePosNonzeroError {
|
||||
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
||||
ParsePosNonzeroError::Creation(err)
|
||||
}
|
||||
// TODO: add another error conversion function here.
|
||||
}
|
||||
|
||||
fn parse_pos_nonzero(s: &str)
|
||||
-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
|
||||
{
|
||||
// TODO: change this to return an appropriate error instead of panicking
|
||||
// when `parse()` returns an error.
|
||||
let x: i64 = s.parse().unwrap();
|
||||
PositiveNonzeroInteger::new(x)
|
||||
.map_err(ParsePosNonzeroError::from_creation)
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_error() {
|
||||
// We can't construct a ParseIntError, so we have to pattern match.
|
||||
assert!(matches!(
|
||||
parse_pos_nonzero("not a number"),
|
||||
Err(ParsePosNonzeroError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("-555"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("0"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive() {
|
||||
let x = PositiveNonzeroInteger::new(42);
|
||||
assert!(x.is_ok());
|
||||
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
// errorsn.rs
|
||||
// This is a bigger error exercise than the previous ones!
|
||||
// You can do it! :)
|
||||
//
|
||||
// Edit the `read_and_validate` function ONLY. Don't create any Errors
|
||||
// that do not already exist.
|
||||
//
|
||||
// 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?
|
||||
//
|
||||
// Execute `rustlings hint errorsn` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
// PositiveNonzeroInteger is a struct defined below the tests.
|
||||
fn read_and_validate(b: &mut dyn 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
|
||||
}
|
||||
|
||||
//
|
||||
// Nothing below this needs to be modified
|
||||
//
|
||||
|
||||
// This is a test helper function that turns a &str into a BufReader.
|
||||
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn 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 {
|
||||
let description = match *self {
|
||||
CreationError::Negative => "Number is negative",
|
||||
CreationError::Zero => "Number is zero",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {}
|
||||
@@ -1,6 +1,8 @@
|
||||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// Execute `rustlings hint generics1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// Execute `rustlings hint generics2` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Wrapper {
|
||||
|
||||
15
exercises/move_semantics/move_semantics5.rs
Normal file
15
exercises/move_semantics/move_semantics5.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
// move_semantics5.rs
|
||||
// Make me compile without adding, removing, or changing any of the
|
||||
// lines in `main()`.
|
||||
// Execute `rustlings hint move_semantics5` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut x = 100;
|
||||
let y = &mut x;
|
||||
let z = &mut *y;
|
||||
*y += 100;
|
||||
*z += 1000;
|
||||
assert_eq!(x, 1200);
|
||||
}
|
||||
19
exercises/option/option3.rs
Normal file
19
exercises/option/option3.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
// option3.rs
|
||||
// Make me compile! Execute `rustlings hint option3` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y: Option<Point> = Some(Point { x: 100, y: 200 });
|
||||
|
||||
match y {
|
||||
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),
|
||||
_ => println!("no match"),
|
||||
}
|
||||
y; // Fix without deleting this line.
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
||||
// more than 40 at once, each apple only costs 1! Write a function that calculates
|
||||
// the price of an order of apples given the order amount. No hints this time!
|
||||
// the price of an order of apples given the quantity bought. No hints this time!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#[test]
|
||||
fn verify_test() {
|
||||
let price1 = calculate_apple_price(35);
|
||||
let price2 = calculate_apple_price(65);
|
||||
let price2 = calculate_apple_price(40);
|
||||
let price3 = calculate_apple_price(65);
|
||||
|
||||
assert_eq!(70, price1);
|
||||
assert_eq!(65, price2);
|
||||
assert_eq!(80, price2);
|
||||
assert_eq!(65, price3);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// iterators1.rs
|
||||
//
|
||||
//
|
||||
// Make me compile by filling in the `???`s
|
||||
//
|
||||
// When performing operations on elements within a collection, iterators are essential.
|
||||
// This module helps you get familiar with the structure of using an iterator and
|
||||
// This module helps you get familiar with the structure of using an iterator and
|
||||
// how to go through elements within an iterable collection.
|
||||
//
|
||||
//
|
||||
// Execute `rustlings hint iterators1` for hints :D
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
// imperative style for loops. Recreate this counting functionality using
|
||||
// iterators. Only the two iterator methods (count_iterator and
|
||||
// count_collection_iterator) need to be modified.
|
||||
// Execute `rustlings hint
|
||||
// iterators5` for hints.
|
||||
// Execute `rustlings hint iterators5` for hints.
|
||||
//
|
||||
// Make the code compile and the tests pass.
|
||||
|
||||
@@ -16,7 +15,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Progress {
|
||||
None,
|
||||
Some,
|
||||
|
||||
@@ -31,7 +31,7 @@ impl Package {
|
||||
}
|
||||
|
||||
fn get_fees(&self, cents_per_gram: i32) -> ??? {
|
||||
// Something goes here...
|
||||
// Something goes here...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let number = "T-H-R-E-E";
|
||||
let number = "T-H-R-E-E"; // don't change this line
|
||||
println!("Spell a Number : {}", number);
|
||||
number = 3;
|
||||
println!("Number plus two is : {}", number + 2);
|
||||
|
||||
138
info.toml
138
info.toml
@@ -210,6 +210,21 @@ So the end goal is to:
|
||||
- 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`"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics5"
|
||||
path = "exercises/move_semantics/move_semantics5.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Carefully reason about the range in which each mutable reference is in
|
||||
vogue. Does it help to update the value of referent (x) immediately after
|
||||
the mutable reference is taken? Read more about 'Mutable References'
|
||||
in the book's section References and Borrowing':
|
||||
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references.
|
||||
|
||||
Additional hint:
|
||||
If you can't add, change, or remove any statements in `main()`, can you
|
||||
reorder them in a way that lets the program compile?"""
|
||||
|
||||
# PRIMITIVE TYPES
|
||||
|
||||
[[exercises]]
|
||||
@@ -475,42 +490,61 @@ hint = """
|
||||
If other functions can return a `Result`, why shouldn't `main`?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "errorsn"
|
||||
path = "exercises/error_handling/errorsn.rs"
|
||||
name = "errors4"
|
||||
path = "exercises/error_handling/errors4.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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.
|
||||
`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 :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "errors5"
|
||||
path = "exercises/error_handling/errors5.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Hint: There are two different possible `Result` types produced within
|
||||
`main()`, which are propagated using `?` operators. How do we declare a
|
||||
return type from `main()` that allows both?
|
||||
|
||||
Another hint: under the hood, the `?` operator calls `From::from`
|
||||
on the error value to convert it to a boxed trait object, a Box<dyn 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.
|
||||
on the error value to convert it to a boxed trait object, a
|
||||
`Box<dyn 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/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
|
||||
This exercise uses some concepts that we won't get to until later in the
|
||||
course, like `Box` and the `From` trait. It's not important to understand
|
||||
them in detail right now, but you can read ahead if you like.
|
||||
|
||||
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)`.
|
||||
Read more about boxing errors:
|
||||
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html
|
||||
|
||||
Read more about using the `?` operator with boxed errors:
|
||||
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html
|
||||
"""
|
||||
|
||||
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"""
|
||||
[[exercises]]
|
||||
name = "errors6"
|
||||
path = "exercises/error_handling/errors6.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
This exercise uses a completed version of `PositiveNonzeroInteger` from
|
||||
errors4.
|
||||
|
||||
Below the line that TODO asks you to change, there is an example of using
|
||||
the `map_err()` method on a `Result` to transform one type of error into
|
||||
another. Try using something similar on the `Result` from `parse()`. You
|
||||
might use the `?` operator to return early from the function, or you might
|
||||
use a `match` expression, or maybe there's another way!
|
||||
|
||||
You can create another function inside `impl ParsePosNonzeroError` to use
|
||||
with `map_err()`.
|
||||
|
||||
Read more about `map_err()` in the `std::result` documentation:
|
||||
https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err"""
|
||||
|
||||
# Generics
|
||||
|
||||
@@ -546,7 +580,7 @@ ReportCard struct generic, but also the correct property - you will need to chan
|
||||
of the struct slightly too...you can do it!
|
||||
"""
|
||||
|
||||
# OPTIONS / RESULTS
|
||||
# OPTIONS
|
||||
|
||||
[[exercises]]
|
||||
name = "option1"
|
||||
@@ -579,13 +613,14 @@ Also see Option::flatten
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "result1"
|
||||
path = "exercises/error_handling/result1.rs"
|
||||
mode = "test"
|
||||
name = "option3"
|
||||
path = "exercises/option/option3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
`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 :)"""
|
||||
The compiler says a partial move happened in the `match`
|
||||
statement. How can this be avoided? The compiler shows the correction
|
||||
needed. After making the correction as suggested by the compiler, do
|
||||
read: https://doc.rust-lang.org/std/keyword.ref.html"""
|
||||
|
||||
# TRAITS
|
||||
|
||||
@@ -737,7 +772,10 @@ The division_results variable needs to be collected into a collection type.
|
||||
The result_with_list function needs to return a single Result where the success
|
||||
case is a vector of integers and the failure case is a DivisionError.
|
||||
|
||||
The list_of_results function needs to return a vector of results."""
|
||||
The list_of_results function needs to return a vector of results.
|
||||
|
||||
See https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect for how
|
||||
the `FromIterator` trait is used in `collect()`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "iterators4"
|
||||
@@ -763,7 +801,10 @@ test count_iterator.
|
||||
The collection variable in count_collection_iterator is a slice of HashMaps. It
|
||||
needs to be converted into an iterator in order to use the iterator methods.
|
||||
|
||||
The fold method can be useful in the count_collection_iterator function."""
|
||||
The fold method can be useful in the count_collection_iterator function.
|
||||
|
||||
For a further challenge, consult the documentation for Iterator to find
|
||||
a different method that could make your code more compact than using fold."""
|
||||
|
||||
# THREADS
|
||||
|
||||
@@ -861,7 +902,15 @@ name = "clippy1"
|
||||
path = "exercises/clippy/clippy1.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
|
||||
Not every floating point value can be represented exactly in binary values in
|
||||
memory. Take a look at the description of
|
||||
https://doc.rust-lang.org/stable/std/primitive.f32.html
|
||||
When using the binary compare operators with floating points you won't compare
|
||||
the floating point values but the binary representation in memory. This is
|
||||
usually not what you would like to do.
|
||||
See the suggestions of the clippy warning in compile output and use the
|
||||
machine epsilon value...
|
||||
https://doc.rust-lang.org/stable/std/primitive.f32.html#associatedconstant.EPSILON"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
@@ -893,7 +942,19 @@ path = "exercises/conversions/try_from_into.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Follow the steps provided right before the `TryFrom` implementation.
|
||||
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html"""
|
||||
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||
|
||||
You might want to look back at the exercise errors5 (or its hints) to remind
|
||||
yourself about how `Box<dyn Error>` works.
|
||||
|
||||
If you're trying to return a string as an error, note that neither `str`
|
||||
nor `String` implements `error::Error`. However, there is an implementation
|
||||
of `From<&str>` for `Box<dyn Error>`. This means you can use `.into()` or
|
||||
the `?` operator to convert your string into the correct error type.
|
||||
|
||||
If you're having trouble with using the `?` operator to convert an error string,
|
||||
recall that `?` works to convert `Err(something)` into the appropriate error
|
||||
type for returning from the function."""
|
||||
|
||||
[[exercises]]
|
||||
name = "as_ref_mut"
|
||||
@@ -909,4 +970,7 @@ mode = "test"
|
||||
hint = """
|
||||
The implementation of FromStr should return an Ok with a Person object,
|
||||
or an Err with an error if the string is not valid.
|
||||
This is almost like the `try_from_into` exercise."""
|
||||
This is almost like the `try_from_into` exercise.
|
||||
|
||||
If you're having trouble with returning the correct error type, see the
|
||||
hints for try_from_into."""
|
||||
|
||||
27
src/main.rs
27
src/main.rs
@@ -23,7 +23,7 @@ mod run;
|
||||
mod verify;
|
||||
|
||||
// In sync with crate version
|
||||
const VERSION: &str = "4.4.0";
|
||||
const VERSION: &str = "4.5.0";
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
||||
@@ -286,13 +286,24 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
|
||||
}
|
||||
|
||||
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
||||
exercises
|
||||
.iter()
|
||||
.find(|e| e.name == name)
|
||||
.unwrap_or_else(|| {
|
||||
println!("No exercise found for '{}'!", name);
|
||||
std::process::exit(1)
|
||||
})
|
||||
if name.eq("next") {
|
||||
exercises
|
||||
.iter()
|
||||
.find(|e| !e.looks_done())
|
||||
.unwrap_or_else(|| {
|
||||
println!("🎉 Congratulations! You have done all the exercises!");
|
||||
println!("🔚 There are no more exercises to do next!");
|
||||
std::process::exit(1)
|
||||
})
|
||||
} else {
|
||||
exercises
|
||||
.iter()
|
||||
.find(|e| e.name == name)
|
||||
.unwrap_or_else(|| {
|
||||
println!("No exercise found for '{}'!", name);
|
||||
std::process::exit(1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user