mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a303d508cf | ||
|
|
44d39112ff | ||
|
|
28020d0c54 | ||
|
|
0ef95947cc | ||
|
|
4ac70a99ae | ||
|
|
bcf14cf677 | ||
|
|
1dae782cd4 | ||
|
|
90cfb6ff28 | ||
|
|
26110da7ca | ||
|
|
30644c9a06 | ||
|
|
033bf1198f | ||
|
|
cdc7d92e57 | ||
|
|
af0e3b8f17 | ||
|
|
04f1d079aa | ||
|
|
9b6c629397 | ||
|
|
5aa467bef2 | ||
|
|
af7ad27f89 | ||
|
|
d6d57bfbb8 | ||
|
|
4f4cfcf3c3 | ||
|
|
fa9f522b7f | ||
|
|
838f9f3008 | ||
|
|
96347df9df | ||
|
|
9334783da3 |
@@ -637,6 +637,24 @@
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pcn",
|
||||
"name": "Peter N",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1056756?v=4",
|
||||
"profile": "https://github.com/pcn",
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "seancad",
|
||||
"name": "seancad",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/47405611?v=4",
|
||||
"profile": "https://github.com/seancad",
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 8,
|
||||
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,3 +1,26 @@
|
||||
<a name="4.3.0"></a>
|
||||
## 4.3.0 (2020-12-29)
|
||||
|
||||
#### Features
|
||||
|
||||
* Rewrite default out text ([44d39112](https://github.com/rust-lang/rustlings/commit/44d39112ff122b29c9793fe52e605df1612c6490))
|
||||
* match exercise order to book chapters (#541) ([033bf119](https://github.com/rust-lang/rustlings/commit/033bf1198fc8bfce1b570e49da7cde010aa552e3))
|
||||
* Crab? (#586) ([fa9f522b](https://github.com/rust-lang/rustlings/commit/fa9f522b7f043d7ef73a39f003a9272dfe72c4f4))
|
||||
* add "rustlings list" command ([838f9f30](https://github.com/rust-lang/rustlings/commit/838f9f30083d0b23fd67503dcf0fbeca498e6647))
|
||||
* **try_from_into:** remove duplicate annotation ([04f1d079](https://github.com/rust-lang/rustlings/commit/04f1d079aa42a2f49af694bc92c67d731d31a53f))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* update structs README ([bcf14cf6](https://github.com/rust-lang/rustlings/commit/bcf14cf677adb3a38a3ac3ca53f3c69f61153025))
|
||||
* added missing exercises to info.toml ([90cfb6ff](https://github.com/rust-lang/rustlings/commit/90cfb6ff28377531bfc34acb70547bdb13374f6b))
|
||||
* gives a bit more context to magic number ([30644c9a](https://github.com/rust-lang/rustlings/commit/30644c9a062b825c0ea89435dc59f0cad86b110e))
|
||||
* **functions2:** Change signature to trigger precise error message: (#605) ([0ef95947](https://github.com/rust-lang/rustlings/commit/0ef95947cc30482e63a7045be6cc2fb6f6dcb4cc))
|
||||
* **structs1:** Adjust wording (#573) ([9334783d](https://github.com/rust-lang/rustlings/commit/9334783da31d821cc59174fbe8320df95828926c))
|
||||
* **try_from_into:**
|
||||
* type error ([4f4cfcf3](https://github.com/rust-lang/rustlings/commit/4f4cfcf3c36c8718c7c170c9c3a6935e6ef0618c))
|
||||
* Update description (#584) ([96347df9](https://github.com/rust-lang/rustlings/commit/96347df9df294f01153b29d9ad4ba361f665c755))
|
||||
* **vec1:** Have test compare every element in a and v ([9b6c6293](https://github.com/rust-lang/rustlings/commit/9b6c629397b24b944f484f5b2bbd8144266b5695))
|
||||
|
||||
<a name="4.2.0"></a>
|
||||
## 4.2.0 (2020-11-07)
|
||||
|
||||
|
||||
590
Cargo.lock
generated
590
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "4.2.0"
|
||||
version = "4.3.0"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
26
README.md
26
README.md
@@ -1,9 +1,9 @@
|
||||

|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# rustlings 🦀❤️ [](https://buildkite.com/mokou/rustlings)
|
||||
# rustlings 🦀❤️
|
||||
|
||||
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
|
||||
|
||||
@@ -61,7 +61,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/4.2.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
git checkout tags/4.3.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
@@ -118,6 +118,24 @@ cargo uninstall rustlings
|
||||
rm -r rustlings/ # or on Windows: rmdir /s rustlings
|
||||
```
|
||||
|
||||
## Uninstalling Rustlings
|
||||
|
||||
If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created
|
||||
for you:
|
||||
|
||||
``` bash
|
||||
rm -rf rustlings # or your custom folder name, if you chose and or renamed it
|
||||
```
|
||||
|
||||
Second, since Rustlings got installed via `cargo install`, it's only reasonable to assume that you can also remove it using Cargo, and
|
||||
exactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary:
|
||||
|
||||
``` bash
|
||||
cargo uninstall rustlings
|
||||
```
|
||||
|
||||
Now you should be done!
|
||||
|
||||
## Completion
|
||||
|
||||
Rustlings isn't done; there are a couple of sections that are very experimental and don't have proper documentation. These include:
|
||||
@@ -233,6 +251,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://darnuria.eu"><img src="https://avatars1.githubusercontent.com/u/2827553?v=4" width="100px;" alt=""/><br /><sub><b>Axel Viala</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=darnuria" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://sazid.github.io"><img src="https://avatars1.githubusercontent.com/u/2370167?v=4" width="100px;" alt=""/><br /><sub><b>Mohammed Sazid Al Rashid</b></sub></a><br /><a href="#content-sazid" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=sazid" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://codingthemsoftly.com"><img src="https://avatars1.githubusercontent.com/u/17479099?v=4" width="100px;" alt=""/><br /><sub><b>Caleb Webber</b></sub></a><br /><a href="#maintenance-seeplusplus" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/pcn"><img src="https://avatars2.githubusercontent.com/u/1056756?v=4" width="100px;" alt=""/><br /><sub><b>Peter N</b></sub></a><br /><a href="#maintenance-pcn" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/seancad"><img src="https://avatars1.githubusercontent.com/u/47405611?v=4" width="100px;" alt=""/><br /><sub><b>seancad</b></sub></a><br /><a href="#maintenance-seancad" title="Maintenance">🚧</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
steps:
|
||||
- label: "Test with stable"
|
||||
command: rustup run stable cargo test
|
||||
- label: "Test with beta"
|
||||
command: rustup run beta cargo test
|
||||
@@ -1,19 +1,25 @@
|
||||
Thanks for installing Rustlings!
|
||||
|
||||
Is this your first time?
|
||||
Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
||||
going to teach you a lot of things about Rust, but before we can get
|
||||
started, here's a couple of notes about how Rustlings operates:
|
||||
|
||||
Let's make sure you're up to speed:
|
||||
- You have Rust installed, preferably via `rustup`
|
||||
- You have `~/.cargo/bin` added to your PATH variable
|
||||
- You have cloned this repository (https://github.com/rust-lang/rustlings)
|
||||
- You have installed Rust language support for your editor
|
||||
- You have locally installed the `rustlings` command by running an
|
||||
installation script or manually executing:
|
||||
1. The central concept behind Rustlings is that you solve exercises. These
|
||||
exercises usually have some sort of syntax error in them, which will cause
|
||||
them to fail compliation or testing. Sometimes there's a logic error instead
|
||||
of a syntax error. No matter what error, it's your job to find it and fix it!
|
||||
You'll know when you fixed it because then, the exercise will compile and
|
||||
Rustlings will be able to move on to the next exercise.
|
||||
2. If you run Rustlings in watch mode (which we recommend), it'll automatically
|
||||
start with the first exercise. Don't get confused by an error message popping
|
||||
up as soon as you run Rustlings! This is part of the exercise that you're
|
||||
supposed to solve, so open the exercise file in an editor and start your
|
||||
detective work!
|
||||
3. If you're stuck on an exercise, there is a helpful hint you can view by typing
|
||||
'hint' (in watch mode), or running `rustlings hint myexercise`.
|
||||
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
|
||||
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
|
||||
and sometimes, other learners do too so you can help each other out!
|
||||
|
||||
cargo install --force --path .
|
||||
|
||||
If you've done all of this (or even most of it), congrats! You're ready
|
||||
to start working with Rust.
|
||||
|
||||
To get started, run `rustlings watch` in order to get the first exercise.
|
||||
Make sure to have your editor open!
|
||||
Got all that? Great! To get started, run `rustlings watch` in order to get the first
|
||||
exercise. Make sure to have your editor open!
|
||||
|
||||
24
exercises/README.md
Normal file
24
exercises/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Exercise to Book Chapter mapping
|
||||
|
||||
| Exercise | Book Chapter |
|
||||
|------------------------|--------------|
|
||||
| variables | §3.1 |
|
||||
| functions | §3.3 |
|
||||
| if | §3.5 |
|
||||
| move_semantics | §4.1 |
|
||||
| primitive_types | §4.3 |
|
||||
| structs | §5.1 |
|
||||
| enums | §6 |
|
||||
| modules | §7.2 |
|
||||
| collections | §8.1 |
|
||||
| strings | §8.2 |
|
||||
| error_handling | §9 |
|
||||
| generics | §10 |
|
||||
| option | §10.1 |
|
||||
| traits | §10.2 |
|
||||
| tests | §11.1 |
|
||||
| standard_library_types | §13.2 |
|
||||
| threads | §16.1 |
|
||||
| macros | §19.6 |
|
||||
| clippy | n/a |
|
||||
| conversions | n/a |
|
||||
@@ -20,6 +20,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_array_and_vec_similarity() {
|
||||
let (a, v) = array_and_vec();
|
||||
assert!(a.iter().zip(v.iter()).all(|(x, y)| x == y));
|
||||
assert_eq!(a, v[..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ struct Color {
|
||||
|
||||
// Your task is to complete this implementation
|
||||
// and return an Ok result of inner type Color.
|
||||
// You need create implementation for a tuple of three integer,
|
||||
// an array of three integer and slice of integer.
|
||||
// You need to create an implementation for a tuple of three integers,
|
||||
// an array of three integers and a slice of integers.
|
||||
//
|
||||
// Note, that implementation for tuple and array will be checked at compile-time,
|
||||
// but slice implementation need check slice length!
|
||||
// Also note, that chunk of correct rgb color must be integer in range 0..=255.
|
||||
// Note that the implementation for tuple and array will be checked at compile time,
|
||||
// but the slice implementation needs to check the slice length!
|
||||
// Also note that correct RGB color values must be integers in the 0..=255 range.
|
||||
|
||||
// Tuple implementation
|
||||
impl TryFrom<(i16, i16, i16)> for Color {
|
||||
@@ -88,21 +88,20 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_positive() {
|
||||
let c: Color = [1000, 10000, 256].try_into();
|
||||
let c: Result<Color, String> = [1000, 10000, 256].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_negative() {
|
||||
let c: Color = [-10, -256, -1].try_into();
|
||||
let c: Result<Color, String> = [-10, -256, -1].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_array_sum() {
|
||||
let c: Color = [-1, 255, 255].try_into();
|
||||
let c: Result<Color, String> = [-1, 255, 255].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
#[test]
|
||||
fn test_array_correct() {
|
||||
let c: Result<Color, String> = [183, 65, 14].try_into();
|
||||
assert_eq!(
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
call_me(3);
|
||||
}
|
||||
|
||||
fn call_me(num) {
|
||||
fn call_me(num:) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ Rust has three struct types: a classic c struct, a tuple struct, and a unit stru
|
||||
|
||||
#### Book Sections
|
||||
|
||||
- [Structures](https://doc.rust-lang.org/rust-by-example/custom_types/structs.html)
|
||||
- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// threads1.rs
|
||||
// Make this compile! Execute `rustlings hint threads1` for hints :)
|
||||
// The idea is the thread spawned on line 21 is completing jobs while the main thread is
|
||||
// monitoring progress until 10 jobs are completed. If you see 6 lines
|
||||
// monitoring progress until 10 jobs are completed. Because of the difference between the
|
||||
// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines
|
||||
// of "waiting..." and the program ends without timing out when running,
|
||||
// you've got it :)
|
||||
|
||||
|
||||
526
info.toml
526
info.toml
@@ -71,31 +71,6 @@ Read more about constants under 'Differences Between Variables and Constants' in
|
||||
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
|
||||
"""
|
||||
|
||||
# IF
|
||||
|
||||
[[exercises]]
|
||||
name = "if1"
|
||||
path = "exercises/if/if1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "if2"
|
||||
path = "exercises/if/if2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
For that first compiler error, it's important in Rust that each conditional
|
||||
block return the same type! To get the tests passing, you will need a couple
|
||||
conditions checking different input values."""
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
[[exercises]]
|
||||
@@ -146,6 +121,31 @@ 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`"""
|
||||
|
||||
# IF
|
||||
|
||||
[[exercises]]
|
||||
name = "if1"
|
||||
path = "exercises/if/if1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "if2"
|
||||
path = "exercises/if/if2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
For that first compiler error, it's important in Rust that each conditional
|
||||
block return the same type! To get the tests passing, you will need a couple
|
||||
conditions checking different input values."""
|
||||
|
||||
# TEST 1
|
||||
|
||||
[[exercises]]
|
||||
@@ -154,6 +154,62 @@ path = "exercises/quiz1.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# MOVE SEMANTICS
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics1"
|
||||
path = "exercises/move_semantics/move_semantics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
|
||||
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
|
||||
where the error is."""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics2"
|
||||
path = "exercises/move_semantics/move_semantics2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So `vec0` is being *moved* into the function `fill_vec` when we call it on
|
||||
line 10, which means it gets dropped at the end of `fill_vec`, which means we
|
||||
can't use `vec0` again on line 13 (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!`"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics3"
|
||||
path = "exercises/move_semantics/move_semantics3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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 :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics4"
|
||||
path = "exercises/move_semantics/move_semantics4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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`"""
|
||||
|
||||
# PRIMITIVE TYPES
|
||||
|
||||
[[exercises]]
|
||||
@@ -225,12 +281,13 @@ name = "structs1"
|
||||
path = "exercises/structs/structs1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Rust has more than one type of struct. Both variants are used to package related data together.
|
||||
On the one hand, there are normal, or classic, structs. These are named collections of related data stored in fields.
|
||||
The other variant is tuple structs. Basically just named tuples.
|
||||
In this exercise you need to implement one of each kind.
|
||||
Rust has more than one type of struct. Three actually, all variants are used to package related data together.
|
||||
There are normal (or classic) structs. These are named collections of related data stored in fields.
|
||||
Tuple structs are basically just named tuples.
|
||||
Finally, Unit structs. These don't have and fields and are useful for generics.
|
||||
|
||||
Read more about structs in The Book: https://doc.rust-lang.org/stable/book/ch05-00-structs.html"""
|
||||
In this exercise you need to complete and implement one of each kind.
|
||||
Read more about structs in The Book: https://doc.rust-lang.org/book/ch05-01-defining-structs.html"""
|
||||
|
||||
[[exercises]]
|
||||
name = "structs2"
|
||||
@@ -254,37 +311,6 @@ For calculate_transport_fees: Bigger is more expensive usually, we don't have si
|
||||
|
||||
Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
|
||||
|
||||
# STRINGS
|
||||
|
||||
[[exercises]]
|
||||
name = "strings1"
|
||||
path = "exercises/strings/strings1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "strings2"
|
||||
path = "exercises/strings/strings2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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
|
||||
9, though, that will coerce the `String` into a string slice."""
|
||||
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
name = "quiz2"
|
||||
path = "exercises/quiz2.rs"
|
||||
mode = "compile"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# ENUMS
|
||||
|
||||
[[exercises]]
|
||||
@@ -308,46 +334,6 @@ path = "exercises/enums/enums3.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# TESTS
|
||||
|
||||
[[exercises]]
|
||||
name = "tests1"
|
||||
path = "exercises/tests/tests1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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 :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests2"
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests3"
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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())`."""
|
||||
|
||||
# TEST 3
|
||||
|
||||
[[exercises]]
|
||||
name = "quiz3"
|
||||
path = "exercises/quiz3.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# MODULES
|
||||
|
||||
[[exercises]]
|
||||
@@ -378,13 +364,10 @@ path = "exercises/collections/vec1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
In Rust, there are two ways to define a Vector.
|
||||
|
||||
1. One way is to use the `Vec::new()` function to create a new vector
|
||||
and fill it with the `push()` method.
|
||||
|
||||
2. The second way, which is simpler is to use the `vec![]` macro and
|
||||
define your elements inside the square brackets.
|
||||
|
||||
Check this chapter: https://doc.rust-lang.org/stable/book/ch08-01-vectors.html
|
||||
of the Rust book to learn more.
|
||||
"""
|
||||
@@ -396,7 +379,6 @@ mode = "test"
|
||||
hint = """
|
||||
Hint 1: `i` is each element from the Vec as they are being iterated.
|
||||
Can you try multiplying this?
|
||||
|
||||
Hint 2: Check the suggestion from the compiler error ;)
|
||||
"""
|
||||
|
||||
@@ -407,7 +389,6 @@ mode = "test"
|
||||
hint = """
|
||||
Hint 1: Take a look at the return type of the function to figure out
|
||||
the type for the `basket`.
|
||||
|
||||
Hint 2: Number of fruits should be at least 5. And you have to put
|
||||
at least three different types of fruits.
|
||||
"""
|
||||
@@ -418,115 +399,40 @@ path = "exercises/collections/hashmap2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Use the `entry()` and `or_insert()` methods of `HashMap` to achieve this.
|
||||
|
||||
Learn more at https://doc.rust-lang.org/stable/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value
|
||||
"""
|
||||
|
||||
# MACROS
|
||||
# STRINGS
|
||||
|
||||
[[exercises]]
|
||||
name = "macros1"
|
||||
path = "exercises/macros/macros1.rs"
|
||||
name = "strings1"
|
||||
path = "exercises/strings/strings1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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`."""
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros2"
|
||||
path = "exercises/macros/macros2.rs"
|
||||
name = "strings2"
|
||||
path = "exercises/strings/strings2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Macros don't quite play by the same rules as the rest of Rust, in terms of
|
||||
what's available where.
|
||||
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
|
||||
9, though, that will coerce the `String` into a string slice."""
|
||||
|
||||
Unlike other things in Rust, the order of "where you define a macro" versus
|
||||
"where you use it" actually matters."""
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
name = "macros3"
|
||||
path = "exercises/macros/macros3.rs"
|
||||
name = "quiz2"
|
||||
path = "exercises/quiz2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros4"
|
||||
path = "exercises/macros/macros4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
# TEST 4
|
||||
|
||||
[[exercises]]
|
||||
name = "quiz4"
|
||||
path = "exercises/quiz4.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# MOVE SEMANTICS
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics1"
|
||||
path = "exercises/move_semantics/move_semantics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
|
||||
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
|
||||
where the error is."""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics2"
|
||||
path = "exercises/move_semantics/move_semantics2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So `vec0` is being *moved* into the function `fill_vec` when we call it on
|
||||
line 10, which means it gets dropped at the end of `fill_vec`, which means we
|
||||
can't use `vec0` again on line 13 (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!`"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics3"
|
||||
path = "exercises/move_semantics/move_semantics3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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 :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics4"
|
||||
path = "exercises/move_semantics/move_semantics4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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`"""
|
||||
|
||||
# ERROR HANDLING
|
||||
|
||||
[[exercises]]
|
||||
@@ -606,6 +512,40 @@ 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"""
|
||||
|
||||
# Generics
|
||||
|
||||
[[exercises]]
|
||||
name = "generics1"
|
||||
path = "exercises/generics/generics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Vectors in rust make use of generics to create dynamically sized arrays of any type.
|
||||
You need to tell the compiler what type we are pushing onto this vector."""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics2"
|
||||
path = "exercises/generics/generics2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Currently we are wrapping only values of type 'u32'.
|
||||
Maybe we could update the explicit references to this data type somehow?
|
||||
|
||||
If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics3"
|
||||
path = "exercises/generics/generics3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
To find the best solution to this challenge you're going to need to think back to your
|
||||
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
|
||||
|
||||
This is definitely harder than the last two exercises! You need to think about not only making the
|
||||
ReportCard struct generic, but also the correct property - you will need to change the implementation
|
||||
of the struct slightly too...you can do it!
|
||||
"""
|
||||
|
||||
# OPTIONS / RESULTS
|
||||
|
||||
[[exercises]]
|
||||
@@ -648,21 +588,67 @@ hint = """
|
||||
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 :)"""
|
||||
|
||||
# CLIPPY
|
||||
# TRAITS
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy1"
|
||||
path = "exercises/clippy/clippy1.rs"
|
||||
mode = "clippy"
|
||||
name = "traits1"
|
||||
path = "exercises/traits/traits1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
|
||||
A discussion about Traits in Rust can be found at:
|
||||
https://doc.rust-lang.org/book/ch10-02-traits.html
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
path = "exercises/clippy/clippy2.rs"
|
||||
mode = "clippy"
|
||||
name = "traits2"
|
||||
path = "exercises/traits/traits2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
`for` loops over Option values are more clearly expressed as an `if let`"""
|
||||
Notice how the trait takes ownership of 'self',and returns `Self'.
|
||||
Try mutating the incoming string vector.
|
||||
|
||||
Vectors provide suitable methods for adding an element at the end. See
|
||||
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
|
||||
|
||||
# TESTS
|
||||
|
||||
[[exercises]]
|
||||
name = "tests1"
|
||||
path = "exercises/tests/tests1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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 :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests2"
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests3"
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
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())`."""
|
||||
|
||||
# TEST 3
|
||||
|
||||
[[exercises]]
|
||||
name = "quiz3"
|
||||
path = "exercises/quiz3.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# STANDARD LIBRARY TYPES
|
||||
|
||||
@@ -705,12 +691,8 @@ Step 1:
|
||||
We need to apply something to the collection `my_fav_fruits` before we start to go through
|
||||
it. What could that be? Take a look at the struct definition for a vector for inspiration:
|
||||
https://doc.rust-lang.org/std/vec/struct.Vec.html.
|
||||
|
||||
|
||||
Step 2 & step 2.1:
|
||||
Very similar to the lines above and below. You've got this!
|
||||
|
||||
|
||||
Step 3:
|
||||
An iterator goes through all elements in a collection, but what if we've run out of
|
||||
elements? What should we expect here? If you're stuck, take a look at
|
||||
@@ -760,62 +742,6 @@ a mutable variable. Or, you might write code utilizing recursion
|
||||
and a match clause. In Rust you can take another functional
|
||||
approach, computing the factorial elegantly with ranges and iterators."""
|
||||
|
||||
# TRAITS
|
||||
|
||||
[[exercises]]
|
||||
name = "traits1"
|
||||
path = "exercises/traits/traits1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
A discussion about Traits in Rust can be found at:
|
||||
https://doc.rust-lang.org/book/ch10-02-traits.html
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "traits2"
|
||||
path = "exercises/traits/traits2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Notice how the trait takes ownership of 'self',and returns `Self'.
|
||||
Try mutating the incoming string vector.
|
||||
|
||||
Vectors provide suitable methods for adding an element at the end. See
|
||||
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
|
||||
|
||||
# Generics
|
||||
|
||||
[[exercises]]
|
||||
name = "generics1"
|
||||
path = "exercises/generics/generics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Vectors in rust make use of generics to create dynamically sized arrays of any type.
|
||||
You need to tell the compiler what type we are pushing onto this vector."""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics2"
|
||||
path = "exercises/generics/generics2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Currently we are wrapping only values of type 'u32'.
|
||||
Maybe we could update the explicit references to this data type somehow?
|
||||
|
||||
If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics3"
|
||||
path = "exercises/generics/generics3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
To find the best solution to this challenge you're going to need to think back to your
|
||||
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
|
||||
|
||||
This is definitely harder than the last two exercises! You need to think about not only making the
|
||||
ReportCard struct generic, but also the correct property - you will need to change the implementation
|
||||
of the struct slightly too...you can do it!
|
||||
"""
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
@@ -855,6 +781,72 @@ 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 :)"""
|
||||
|
||||
# MACROS
|
||||
|
||||
[[exercises]]
|
||||
name = "macros1"
|
||||
path = "exercises/macros/macros1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros2"
|
||||
path = "exercises/macros/macros2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros3"
|
||||
path = "exercises/macros/macros3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros4"
|
||||
path = "exercises/macros/macros4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
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."""
|
||||
|
||||
# TEST 4
|
||||
|
||||
[[exercises]]
|
||||
name = "quiz4"
|
||||
path = "exercises/quiz4.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# CLIPPY
|
||||
|
||||
[[exercises]]
|
||||
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"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
path = "exercises/clippy/clippy2.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
`for` loops over Option values are more clearly expressed as an `if let`"""
|
||||
|
||||
# TYPE CONVERSIONS
|
||||
|
||||
[[exercises]]
|
||||
|
||||
30
src/main.rs
30
src/main.rs
@@ -25,7 +25,7 @@ mod verify;
|
||||
fn main() {
|
||||
let matches = App::new("rustlings")
|
||||
.version(crate_version!())
|
||||
.author("Olivia Hugger, Carol Nichols")
|
||||
.author("Marisa, Carol Nichols")
|
||||
.about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
|
||||
.arg(
|
||||
Arg::with_name("nocapture")
|
||||
@@ -54,6 +54,11 @@ fn main() {
|
||||
.about("Returns a hint for the current exercise")
|
||||
.arg(Arg::with_name("name").required(true).index(1)),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("list")
|
||||
.alias("l")
|
||||
.about("Lists the exercises available in rustlings")
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
@@ -88,6 +93,9 @@ fn main() {
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
let verbose = matches.is_present("nocapture");
|
||||
|
||||
if matches.subcommand_matches("list").is_some() {
|
||||
exercises.iter().for_each(|e| println!("{}", e.name));
|
||||
}
|
||||
if let Some(ref matches) = matches.subcommand_matches("run") {
|
||||
let name = matches.value_of("name").unwrap();
|
||||
|
||||
@@ -130,6 +138,26 @@ fn main() {
|
||||
emoji = Emoji("🎉", "★")
|
||||
);
|
||||
println!();
|
||||
println!("+----------------------------------------------------+");
|
||||
println!("| You made it to the Fe-nish line! |");
|
||||
println!("+-------------------------- ------------------------+");
|
||||
println!(" \\/ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
|
||||
println!(" ░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒ ");
|
||||
println!(" ▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ");
|
||||
println!();
|
||||
println!("We hope you enjoyed learning about the various aspects of Rust!");
|
||||
println!("If you noticed any issues, please don't hesitate to report them to our repo.");
|
||||
println!("You can also contribute your own exercises to help the greater community!");
|
||||
|
||||
Reference in New Issue
Block a user