Merge remote-tracking branch 'upstream/main' into fix-enum-variant-inconsistency

This commit is contained in:
mo8it 2024-07-05 13:39:50 +02:00
commit 7123c7ae3a
269 changed files with 9826 additions and 7926 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
{
"image": "mcr.microsoft.com/devcontainers/universal:2-linux",
"waitFor": "onCreateCommand",
"onCreateCommand": ".devcontainer/setup.sh",
"updateContentCommand": "cargo build",
"postCreateCommand": "",
"postAttachCommand": {
"server": "rustlings watch"
},
"customizations": {
"vscode": {
"extensions": [
"rust-lang.rust-analyzer"
]
}
}
}

View file

@ -1,7 +0,0 @@
#!/bin/bash
curl https://sh.rustup.rs -sSf | sh -s -- -y
# Update current shell environment variables after install to find rustup
. "$HOME/.cargo/env"
rustup install stable
bash install.sh

View file

@ -2,36 +2,42 @@ name: Rustlings Tests
on: on:
push: push:
branches: [ main ] branches: [main]
pull_request: pull_request:
branches: [ main ] branches: [main]
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
jobs: jobs:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo clippy -- --deny warnings
fmt: fmt:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - uses: DavidAnson/markdownlint-cli2-action@v16
with:
components: rustfmt
- uses: DavidAnson/markdownlint-cli2-action@v9
with: with:
globs: "exercises/**/*.md" globs: "exercises/**/*.md"
- name: Run cargo fmt - name: Run cargo fmt
run: | run: cargo fmt --all -- --check
cargo fmt --all -- --check
test: test:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: swatinem/rust-cache@v2 - uses: swatinem/rust-cache@v2
- name: Run cargo test - name: Run cargo test
run: | run: cargo test
cargo test dev-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: swatinem/rust-cache@v2
- name: Run rustlings dev check
run: cargo run -- dev check --require-solutions

View file

@ -54,10 +54,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
# Setup # Setup
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: swatinem/rust-cache@v2 - uses: swatinem/rust-cache@v2
# If you use any mdbook plugins, here's the place to install them! # If you use any mdbook plugins, here's the place to install them!

33
.gitignore vendored
View file

@ -1,18 +1,23 @@
*.swp # Cargo
target/ target/
**/*.rs.bk Cargo.lock
.DS_Store !/Cargo.lock
*.pdb
exercises/clippy/Cargo.toml # State file
exercises/clippy/Cargo.lock .rustlings-state.txt
rust-project.json
.idea # oranda
.vscode/*
!.vscode/extensions.json
*.iml
*.o
public/ public/
.netlify
# OS
.DS_Store
.direnv/ .direnv/
# Local Netlify folder # Editor
.netlify *.swp
.idea
*.iml
# Ignore file for editors like Helix
.ignore

View file

@ -1,7 +0,0 @@
tasks:
- init: /workspace/rustlings/install.sh
command: /workspace/.cargo/bin/rustlings watch
vscode:
extensions:
- rust-lang.rust-analyzer@0.3.1348

7
.typos.toml Normal file
View file

@ -0,0 +1,7 @@
[files]
extend-exclude = [
"CHANGELOG.md",
]
[default.extend-words]
"ratatui" = "ratatui"

View file

@ -1,5 +0,0 @@
{
"recommendations": [
"rust-lang.rust-analyzer"
]
}

View file

@ -1,369 +0,0 @@
## Authors
This file lists the people that have contributed to this project.
Excluded from this list are @carols10cents and @diannasoreil, the principal
authors.
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://carol-nichols.com"><img src="https://avatars2.githubusercontent.com/u/193874?v=4?s=100" width="100px;" alt="Carol (Nichols &#124;&#124; Goulding)"/><br /><sub><b>Carol (Nichols &#124;&#124; Goulding)</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=carols10cents" title="Code">💻</a> <a href="#content-carols10cents" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://twitter.com/QuietMisdreavus"><img src="https://avatars2.githubusercontent.com/u/5217170?v=4?s=100" width="100px;" alt="QuietMisdreavus"/><br /><sub><b>QuietMisdreavus</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=QuietMisdreavus" title="Code">💻</a> <a href="#content-QuietMisdreavus" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/robertlugg"><img src="https://avatars0.githubusercontent.com/u/6054540?v=4?s=100" width="100px;" alt="Robert M Lugg"/><br /><sub><b>Robert M Lugg</b></sub></a><br /><a href="#content-robertlugg" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://hynek.me/about/"><img src="https://avatars3.githubusercontent.com/u/41240?v=4?s=100" width="100px;" alt="Hynek Schlawack"/><br /><sub><b>Hynek Schlawack</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hynek" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://spacekookie.de"><img src="https://avatars0.githubusercontent.com/u/7669898?v=4?s=100" width="100px;" alt="Katharina Fey"/><br /><sub><b>Katharina Fey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=spacekookie" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/lukabavdaz"><img src="https://avatars0.githubusercontent.com/u/9624558?v=4?s=100" width="100px;" alt="lukabavdaz"/><br /><sub><b>lukabavdaz</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lukabavdaz" title="Code">💻</a> <a href="#content-lukabavdaz" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://vestera.as"><img src="https://avatars2.githubusercontent.com/u/4187449?v=4?s=100" width="100px;" alt="Erik Vesteraas"/><br /><sub><b>Erik Vesteraas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=evestera" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Delet0r"><img src="https://avatars1.githubusercontent.com/u/23195618?v=4?s=100" width="100px;" alt="delet0r"/><br /><sub><b>delet0r</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Delet0r" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://phinary.ca"><img src="https://avatars1.githubusercontent.com/u/10522375?v=4?s=100" width="100px;" alt="Shaun Bennett"/><br /><sub><b>Shaun Bennett</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=shaunbennett" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/abagshaw"><img src="https://avatars2.githubusercontent.com/u/8594541?v=4?s=100" width="100px;" alt="Andrew Bagshaw"/><br /><sub><b>Andrew Bagshaw</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=abagshaw" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://ai6ua.net/"><img src="https://avatars2.githubusercontent.com/u/175578?v=4?s=100" width="100px;" alt="Kyle Isom"/><br /><sub><b>Kyle Isom</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kisom" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ColinPitrat"><img src="https://avatars3.githubusercontent.com/u/1541863?v=4?s=100" width="100px;" alt="Colin Pitrat"/><br /><sub><b>Colin Pitrat</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ColinPitrat" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://zacanger.com"><img src="https://avatars3.githubusercontent.com/u/12520493?v=4?s=100" width="100px;" alt="Zac Anger"/><br /><sub><b>Zac Anger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=zacanger" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mgeier"><img src="https://avatars1.githubusercontent.com/u/705404?v=4?s=100" width="100px;" alt="Matthias Geier"/><br /><sub><b>Matthias Geier</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=mgeier" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/cjpearce"><img src="https://avatars1.githubusercontent.com/u/3453268?v=4?s=100" width="100px;" alt="Chris Pearce"/><br /><sub><b>Chris Pearce</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cjpearce" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://yvan-sraka.github.io"><img src="https://avatars2.githubusercontent.com/u/705213?v=4?s=100" width="100px;" alt="Yvan Sraka"/><br /><sub><b>Yvan Sraka</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=yvan-sraka" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/dendi239"><img src="https://avatars3.githubusercontent.com/u/16478650?v=4?s=100" width="100px;" alt="Denys Smirnov"/><br /><sub><b>Denys Smirnov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=dendi239" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/eddyp"><img src="https://avatars2.githubusercontent.com/u/123772?v=4?s=100" width="100px;" alt="eddyp"/><br /><sub><b>eddyp</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=eddyp" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://about.me/BrianKung"><img src="https://avatars1.githubusercontent.com/u/2836167?v=4?s=100" width="100px;" alt="Brian Kung"/><br /><sub><b>Brian Kung</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=briankung" title="Code">💻</a> <a href="#content-briankung" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://rcousineau.gitlab.io"><img src="https://avatars3.githubusercontent.com/u/281039?v=4?s=100" width="100px;" alt="Russell"/><br /><sub><b>Russell</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=miller-time" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://danwilhelm.com"><img src="https://avatars3.githubusercontent.com/u/6137185?v=4?s=100" width="100px;" alt="Dan Wilhelm"/><br /><sub><b>Dan Wilhelm</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=danwilhelm" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Jesse-Cameron"><img src="https://avatars3.githubusercontent.com/u/3723654?v=4?s=100" width="100px;" alt="Jesse"/><br /><sub><b>Jesse</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Jesse-Cameron" title="Code">💻</a> <a href="#content-Jesse-Cameron" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/MrFroop"><img src="https://avatars3.githubusercontent.com/u/196700?v=4?s=100" width="100px;" alt="Fredrik Jambrén"/><br /><sub><b>Fredrik Jambrén</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=MrFroop" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/petemcfarlane"><img src="https://avatars3.githubusercontent.com/u/3472717?v=4?s=100" width="100px;" alt="Pete McFarlane"/><br /><sub><b>Pete McFarlane</b></sub></a><br /><a href="#content-petemcfarlane" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/nkanderson"><img src="https://avatars0.githubusercontent.com/u/4128825?v=4?s=100" width="100px;" alt="nkanderson"/><br /><sub><b>nkanderson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nkanderson" title="Code">💻</a> <a href="#content-nkanderson" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ajaxm"><img src="https://avatars0.githubusercontent.com/u/13360138?v=4?s=100" width="100px;" alt="Ajax M"/><br /><sub><b>Ajax M</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ajaxm" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://dylnuge.com"><img src="https://avatars2.githubusercontent.com/u/118624?v=4?s=100" width="100px;" alt="Dylan Nugent"/><br /><sub><b>Dylan Nugent</b></sub></a><br /><a href="#content-Dylnuge" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/vyaslav"><img src="https://avatars0.githubusercontent.com/u/1385427?v=4?s=100" width="100px;" alt="vyaslav"/><br /><sub><b>vyaslav</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=vyaslav" title="Code">💻</a> <a href="#content-vyaslav" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://join.sfxd.org"><img src="https://avatars1.githubusercontent.com/u/17297466?v=4?s=100" width="100px;" alt="George"/><br /><sub><b>George</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=gdoenlen" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/nyxtom"><img src="https://avatars2.githubusercontent.com/u/222763?v=4?s=100" width="100px;" alt="Thomas Holloway"/><br /><sub><b>Thomas Holloway</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nyxtom" title="Code">💻</a> <a href="#content-nyxtom" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/workingjubilee"><img src="https://avatars1.githubusercontent.com/u/46493976?v=4?s=100" width="100px;" alt="Jubilee"/><br /><sub><b>Jubilee</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=workingjubilee" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/WofWca"><img src="https://avatars1.githubusercontent.com/u/39462442?v=4?s=100" width="100px;" alt="WofWca"/><br /><sub><b>WofWca</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=WofWca" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jrvidal"><img src="https://avatars0.githubusercontent.com/u/1636604?v=4?s=100" width="100px;" alt="Roberto Vidal"/><br /><sub><b>Roberto Vidal</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Documentation">📖</a> <a href="#ideas-jrvidal" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-jrvidal" title="Maintenance">🚧</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jensim"><img src="https://avatars0.githubusercontent.com/u/3663856?v=4?s=100" width="100px;" alt="Jens"/><br /><sub><b>Jens</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jensim" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://rahatah.me/d"><img src="https://avatars3.githubusercontent.com/u/3174006?v=4?s=100" width="100px;" alt="Rahat Ahmed"/><br /><sub><b>Rahat Ahmed</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=rahatarmanahmed" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/AbdouSeck"><img src="https://avatars2.githubusercontent.com/u/6490055?v=4?s=100" width="100px;" alt="Abdou Seck"/><br /><sub><b>Abdou Seck</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=AbdouSeck" title="Code">💻</a> <a href="#content-AbdouSeck" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAbdouSeck" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://codehearts.com"><img src="https://avatars0.githubusercontent.com/u/2885412?v=4?s=100" width="100px;" alt="Katie"/><br /><sub><b>Katie</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=codehearts" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Socratides"><img src="https://avatars3.githubusercontent.com/u/27732983?v=4?s=100" width="100px;" alt="Socrates"/><br /><sub><b>Socrates</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Socratides" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/gnodarse"><img src="https://avatars3.githubusercontent.com/u/46761795?v=4?s=100" width="100px;" alt="gnodarse"/><br /><sub><b>gnodarse</b></sub></a><br /><a href="#content-gnodarse" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/harrisonmetz"><img src="https://avatars1.githubusercontent.com/u/7883408?v=4?s=100" width="100px;" alt="Harrison Metzger"/><br /><sub><b>Harrison Metzger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=harrisonmetz" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/TorbenJ"><img src="https://avatars2.githubusercontent.com/u/9077102?v=4?s=100" width="100px;" alt="Torben Jonas"/><br /><sub><b>Torben Jonas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=TorbenJ" title="Code">💻</a> <a href="#content-TorbenJ" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://paulbissex.com/"><img src="https://avatars0.githubusercontent.com/u/641?v=4?s=100" width="100px;" alt="Paul Bissex"/><br /><sub><b>Paul Bissex</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=pbx" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/sjmann"><img src="https://avatars0.githubusercontent.com/u/6589896?v=4?s=100" width="100px;" alt="Steven Mann"/><br /><sub><b>Steven Mann</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sjmann" title="Code">💻</a> <a href="#content-sjmann" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://smmdb.net/"><img src="https://avatars2.githubusercontent.com/u/5855071?v=4?s=100" width="100px;" alt="Mario Reder"/><br /><sub><b>Mario Reder</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Tarnadas" title="Code">💻</a> <a href="#content-Tarnadas" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://keybase.io/skim"><img src="https://avatars0.githubusercontent.com/u/47347?v=4?s=100" width="100px;" alt="skim"/><br /><sub><b>skim</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sl4m" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/sanjaykdragon"><img src="https://avatars1.githubusercontent.com/u/10261698?v=4?s=100" width="100px;" alt="Sanjay K"/><br /><sub><b>Sanjay K</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sanjaykdragon" title="Code">💻</a> <a href="#content-sanjaykdragon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://www.rohanjain.in"><img src="https://avatars1.githubusercontent.com/u/343499?v=4?s=100" width="100px;" alt="Rohan Jain"/><br /><sub><b>Rohan Jain</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=crodjer" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.saidaspen.se"><img src="https://avatars1.githubusercontent.com/u/7727687?v=4?s=100" width="100px;" alt="Said Aspen"/><br /><sub><b>Said Aspen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=saidaspen" title="Code">💻</a> <a href="#content-saidaspen" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/uce"><img src="https://avatars3.githubusercontent.com/u/1756620?v=4?s=100" width="100px;" alt="Ufuk Celebi"/><br /><sub><b>Ufuk Celebi</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=uce" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/lebedevsergey"><img src="https://avatars2.githubusercontent.com/u/7325764?v=4?s=100" width="100px;" alt="lebedevsergey"/><br /><sub><b>lebedevsergey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lebedevsergey" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/avrong"><img src="https://avatars2.githubusercontent.com/u/6342851?v=4?s=100" width="100px;" alt="Aleksei Trifonov"/><br /><sub><b>Aleksei Trifonov</b></sub></a><br /><a href="#content-avrong" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://drn.ie"><img src="https://avatars2.githubusercontent.com/u/411136?v=4?s=100" width="100px;" alt="Darren Meehan"/><br /><sub><b>Darren Meehan</b></sub></a><br /><a href="#content-Darrenmeehan" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jihchi"><img src="https://avatars1.githubusercontent.com/u/87983?v=4?s=100" width="100px;" alt="Jihchi Lee"/><br /><sub><b>Jihchi Lee</b></sub></a><br /><a href="#content-jihchi" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/bertonha"><img src="https://avatars3.githubusercontent.com/u/1225902?v=4?s=100" width="100px;" alt="Christofer Bertonha"/><br /><sub><b>Christofer Bertonha</b></sub></a><br /><a href="#content-bertonha" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/apatniv"><img src="https://avatars2.githubusercontent.com/u/22565917?v=4?s=100" width="100px;" alt="Vivek Bharath Akupatni"/><br /><sub><b>Vivek Bharath Akupatni</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/DiD92"><img src="https://avatars3.githubusercontent.com/u/6002416?v=4?s=100" width="100px;" alt="Dídac Sementé Fernández"/><br /><sub><b>Dídac Sementé Fernández</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=DiD92" title="Code">💻</a> <a href="#content-DiD92" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/wrobstory"><img src="https://avatars3.githubusercontent.com/u/2601457?v=4?s=100" width="100px;" alt="Rob Story"/><br /><sub><b>Rob Story</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=wrobstory" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/siobhanjacobson"><img src="https://avatars2.githubusercontent.com/u/28983835?v=4?s=100" width="100px;" alt="Siobhan Jacobson"/><br /><sub><b>Siobhan Jacobson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=siobhanjacobson" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/evancarroll/"><img src="https://avatars2.githubusercontent.com/u/19922?v=4?s=100" width="100px;" alt="Evan Carroll"/><br /><sub><b>Evan Carroll</b></sub></a><br /><a href="#content-EvanCarroll" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://www.jawaadmahmood.com"><img src="https://avatars3.githubusercontent.com/u/95606?v=4?s=100" width="100px;" alt="Jawaad Mahmood"/><br /><sub><b>Jawaad Mahmood</b></sub></a><br /><a href="#content-jmahmood" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/GaurangTandon"><img src="https://avatars1.githubusercontent.com/u/6308683?v=4?s=100" width="100px;" alt="Gaurang Tandon"/><br /><sub><b>Gaurang Tandon</b></sub></a><br /><a href="#content-GaurangTandon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/dev-cyprium"><img src="https://avatars1.githubusercontent.com/u/6002628?v=4?s=100" width="100px;" alt="Stefan Kupresak"/><br /><sub><b>Stefan Kupresak</b></sub></a><br /><a href="#content-dev-cyprium" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/greg-el"><img src="https://avatars3.githubusercontent.com/u/45019882?v=4?s=100" width="100px;" alt="Greg Leonard"/><br /><sub><b>Greg Leonard</b></sub></a><br /><a href="#content-greg-el" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://ryanpcmcquen.org"><img src="https://avatars3.githubusercontent.com/u/772937?v=4?s=100" width="100px;" alt="Ryan McQuen"/><br /><sub><b>Ryan McQuen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ryanpcmcquen" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/AnnikaCodes"><img src="https://avatars3.githubusercontent.com/u/56906084?v=4?s=100" width="100px;" alt="Annika"/><br /><sub><b>Annika</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAnnikaCodes" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://darnuria.eu"><img src="https://avatars1.githubusercontent.com/u/2827553?v=4?s=100" width="100px;" alt="Axel Viala"/><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" valign="top" width="12.5%"><a href="https://sazid.github.io"><img src="https://avatars1.githubusercontent.com/u/2370167?v=4?s=100" width="100px;" alt="Mohammed Sazid Al Rashid"/><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" valign="top" width="12.5%"><a href="https://codingthemsoftly.com"><img src="https://avatars1.githubusercontent.com/u/17479099?v=4?s=100" width="100px;" alt="Caleb Webber"/><br /><sub><b>Caleb Webber</b></sub></a><br /><a href="#maintenance-seeplusplus" title="Maintenance">🚧</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/pcn"><img src="https://avatars2.githubusercontent.com/u/1056756?v=4?s=100" width="100px;" alt="Peter N"/><br /><sub><b>Peter N</b></sub></a><br /><a href="#maintenance-pcn" title="Maintenance">🚧</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/seancad"><img src="https://avatars1.githubusercontent.com/u/47405611?v=4?s=100" width="100px;" alt="seancad"/><br /><sub><b>seancad</b></sub></a><br /><a href="#maintenance-seancad" title="Maintenance">🚧</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://willhayworth.com"><img src="https://avatars3.githubusercontent.com/u/181174?v=4?s=100" width="100px;" alt="Will Hayworth"/><br /><sub><b>Will Hayworth</b></sub></a><br /><a href="#content-wsh" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/chrizel"><img src="https://avatars3.githubusercontent.com/u/20802?v=4?s=100" width="100px;" alt="Christian Zeller"/><br /><sub><b>Christian Zeller</b></sub></a><br /><a href="#content-chrizel" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jfchevrette"><img src="https://avatars.githubusercontent.com/u/3001?v=4?s=100" width="100px;" alt="Jean-Francois Chevrette"/><br /><sub><b>Jean-Francois Chevrette</b></sub></a><br /><a href="#content-jfchevrette" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jfchevrette" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jbaber"><img src="https://avatars.githubusercontent.com/u/1908117?v=4?s=100" width="100px;" alt="John Baber-Lucero"/><br /><sub><b>John Baber-Lucero</b></sub></a><br /><a href="#content-jbaber" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tal-zvon"><img src="https://avatars.githubusercontent.com/u/3195851?v=4?s=100" width="100px;" alt="Tal"/><br /><sub><b>Tal</b></sub></a><br /><a href="#content-tal-zvon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/apogeeoak"><img src="https://avatars.githubusercontent.com/u/59737221?v=4?s=100" width="100px;" alt="apogeeoak"/><br /><sub><b>apogeeoak</b></sub></a><br /><a href="#content-apogeeoak" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apogeeoak" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://www.garfieldtech.com/"><img src="https://avatars.githubusercontent.com/u/254863?v=4?s=100" width="100px;" alt="Larry Garfield"/><br /><sub><b>Larry Garfield</b></sub></a><br /><a href="#content-Crell" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/circumspect"><img src="https://avatars.githubusercontent.com/u/40770208?v=4?s=100" width="100px;" alt="circumspect"/><br /><sub><b>circumspect</b></sub></a><br /><a href="#content-circumspect" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/cjwyett"><img src="https://avatars.githubusercontent.com/u/34195737?v=4?s=100" width="100px;" alt="Cyrus Wyett"/><br /><sub><b>Cyrus Wyett</b></sub></a><br /><a href="#content-cjwyett" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/cadolphs"><img src="https://avatars.githubusercontent.com/u/13894820?v=4?s=100" width="100px;" alt="cadolphs"/><br /><sub><b>cadolphs</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cadolphs" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://www.haveneer.com"><img src="https://avatars.githubusercontent.com/u/26146722?v=4?s=100" width="100px;" alt="Pascal H."/><br /><sub><b>Pascal H.</b></sub></a><br /><a href="#content-hpwxf" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://twitter.com/chapeupreto"><img src="https://avatars.githubusercontent.com/u/834048?v=4?s=100" width="100px;" alt="Rod Elias"/><br /><sub><b>Rod Elias</b></sub></a><br /><a href="#content-chapeupreto" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/blerchy"><img src="https://avatars.githubusercontent.com/u/2555355?v=4?s=100" width="100px;" alt="Matt Lebl"/><br /><sub><b>Matt Lebl</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=blerchy" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://flakolefluk.dev"><img src="https://avatars.githubusercontent.com/u/11986564?v=4?s=100" width="100px;" alt="Ignacio Le Fluk"/><br /><sub><b>Ignacio Le Fluk</b></sub></a><br /><a href="#content-flakolefluk" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tlyu"><img src="https://avatars.githubusercontent.com/u/431873?v=4?s=100" width="100px;" alt="Taylor Yu"/><br /><sub><b>Taylor Yu</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=tlyu" title="Code">💻</a> <a href="#content-tlyu" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://zerotask.github.io"><img src="https://avatars.githubusercontent.com/u/20150243?v=4?s=100" width="100px;" alt="Patrick Hintermayer"/><br /><sub><b>Patrick Hintermayer</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Zerotask" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://petkopavlovski.com/"><img src="https://avatars.githubusercontent.com/u/32264020?v=4?s=100" width="100px;" alt="Pete Pavlovski"/><br /><sub><b>Pete Pavlovski</b></sub></a><br /><a href="#content-arthas168" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/k12ish"><img src="https://avatars.githubusercontent.com/u/45272873?v=4?s=100" width="100px;" alt="k12ish"/><br /><sub><b>k12ish</b></sub></a><br /><a href="#content-k12ish" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/hongshaoyang"><img src="https://avatars.githubusercontent.com/u/19281800?v=4?s=100" width="100px;" alt="Shao Yang Hong"/><br /><sub><b>Shao Yang Hong</b></sub></a><br /><a href="#content-hongshaoyang" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/bmacer"><img src="https://avatars.githubusercontent.com/u/13931806?v=4?s=100" width="100px;" alt="Brandon Macer"/><br /><sub><b>Brandon Macer</b></sub></a><br /><a href="#content-bmacer" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/stoiandan"><img src="https://avatars.githubusercontent.com/u/10388612?v=4?s=100" width="100px;" alt="Stoian Dan"/><br /><sub><b>Stoian Dan</b></sub></a><br /><a href="#content-stoiandan" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://about.me/pjdelport"><img src="https://avatars.githubusercontent.com/u/630271?v=4?s=100" width="100px;" alt="Pi Delport"/><br /><sub><b>Pi Delport</b></sub></a><br /><a href="#content-PiDelport" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/sateeshkumarb"><img src="https://avatars.githubusercontent.com/u/429263?v=4?s=100" width="100px;" alt="Sateesh "/><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" valign="top" width="12.5%"><a href="https://github.com/kayuapi"><img src="https://avatars.githubusercontent.com/u/10304328?v=4?s=100" width="100px;" alt="ZC"/><br /><sub><b>ZC</b></sub></a><br /><a href="#content-kayuapi" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/hyperparabolic"><img src="https://avatars.githubusercontent.com/u/12348474?v=4?s=100" width="100px;" alt="hyperparabolic"/><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" valign="top" width="12.5%"><a href="https://www.net4visions.at"><img src="https://avatars.githubusercontent.com/u/5228369?v=4?s=100" width="100px;" alt="arlecchino"/><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" valign="top" width="12.5%"><a href="https://richthofen.io/"><img src="https://avatars.githubusercontent.com/u/7576730?v=4?s=100" width="100px;" alt="Richthofen"/><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" valign="top" width="12.5%"><a href="https://github.com/cseltol"><img src="https://avatars.githubusercontent.com/u/64264529?v=4?s=100" width="100px;" alt="Ivan Nerazumov"/><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" valign="top" width="12.5%"><a href="https://github.com/lauralindzey"><img src="https://avatars.githubusercontent.com/u/65185744?v=4?s=100" width="100px;" alt="lauralindzey"/><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" valign="top" width="12.5%"><a href="https://github.com/sinharaksh1t"><img src="https://avatars.githubusercontent.com/u/28585848?v=4?s=100" width="100px;" alt="Rakshit Sinha"/><br /><sub><b>Rakshit Sinha</b></sub></a><br /><a href="#content-sinharaksh1t" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/dbednar230"><img src="https://avatars.githubusercontent.com/u/54457902?v=4?s=100" width="100px;" alt="Damian"/><br /><sub><b>Damian</b></sub></a><br /><a href="#content-dbednar230" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://benarmstead.co.uk"><img src="https://avatars.githubusercontent.com/u/70973680?v=4?s=100" width="100px;" alt="Ben Armstead"/><br /><sub><b>Ben Armstead</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=benarmstead" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/anuk909"><img src="https://avatars.githubusercontent.com/u/34924662?v=4?s=100" width="100px;" alt="anuk909"/><br /><sub><b>anuk909</b></sub></a><br /><a href="#content-anuk909" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=anuk909" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://granddaifuku.com/"><img src="https://avatars.githubusercontent.com/u/49578068?v=4?s=100" width="100px;" alt="granddaifuku"/><br /><sub><b>granddaifuku</b></sub></a><br /><a href="#content-granddaifuku" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://weilet.me"><img src="https://avatars.githubusercontent.com/u/32561597?v=4?s=100" width="100px;" alt="Weilet"/><br /><sub><b>Weilet</b></sub></a><br /><a href="#content-Weilet" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Millione"><img src="https://avatars.githubusercontent.com/u/38575932?v=4?s=100" width="100px;" alt="LIU JIE"/><br /><sub><b>LIU JIE</b></sub></a><br /><a href="#content-Millione" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/abusch"><img src="https://avatars.githubusercontent.com/u/506344?v=4?s=100" width="100px;" alt="Antoine Büsch"/><br /><sub><b>Antoine Büsch</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=abusch" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://frogtd.com/"><img src="https://avatars.githubusercontent.com/u/31412003?v=4?s=100" width="100px;" alt="frogtd"/><br /><sub><b>frogtd</b></sub></a><br /><a href="#content-frogtd" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/EmisonLu"><img src="https://avatars.githubusercontent.com/u/54395432?v=4?s=100" width="100px;" alt="Zhenghao Lu"/><br /><sub><b>Zhenghao Lu</b></sub></a><br /><a href="#content-EmisonLu" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://soundtrackyourbrand.com"><img src="https://avatars.githubusercontent.com/u/762956?v=4?s=100" width="100px;" alt="Fredrik Enestad"/><br /><sub><b>Fredrik Enestad</b></sub></a><br /><a href="#content-fredr" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://xuesong.pydevops.com"><img src="https://avatars.githubusercontent.com/u/18476085?v=4?s=100" width="100px;" alt="xuesong"/><br /><sub><b>xuesong</b></sub></a><br /><a href="#content-xuesongbj" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/MpdWalsh"><img src="https://avatars.githubusercontent.com/u/48160144?v=4?s=100" width="100px;" alt="Michael Walsh"/><br /><sub><b>Michael Walsh</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=MpdWalsh" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/alirezaghey"><img src="https://avatars.githubusercontent.com/u/26653424?v=4?s=100" width="100px;" alt="alirezaghey"/><br /><sub><b>alirezaghey</b></sub></a><br /><a href="#content-alirezaghey" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/frvannes16"><img src="https://avatars.githubusercontent.com/u/3188475?v=4?s=100" width="100px;" alt="Franklin van Nes"/><br /><sub><b>Franklin van Nes</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=frvannes16" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://nekonako.github.io"><img src="https://avatars.githubusercontent.com/u/46141275?v=4?s=100" width="100px;" alt="nekonako"/><br /><sub><b>nekonako</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nekonako" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tan-zx"><img src="https://avatars.githubusercontent.com/u/67887489?v=4?s=100" width="100px;" alt="ZX"/><br /><sub><b>ZX</b></sub></a><br /><a href="#content-tan-zx" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/sundevilyang"><img src="https://avatars.githubusercontent.com/u/1499214?v=4?s=100" width="100px;" alt="Yang Wen"/><br /><sub><b>Yang Wen</b></sub></a><br /><a href="#content-sundevilyang" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://brandon-high.com"><img src="https://avatars.githubusercontent.com/u/759848?v=4?s=100" width="100px;" alt="Brandon High"/><br /><sub><b>Brandon High</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=highb" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/x-hgg-x"><img src="https://avatars.githubusercontent.com/u/39058530?v=4?s=100" width="100px;" alt="x-hgg-x"/><br /><sub><b>x-hgg-x</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=x-hgg-x" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://kisaragieffective.github.io"><img src="https://avatars.githubusercontent.com/u/48310258?v=4?s=100" width="100px;" alt="Kisaragi"/><br /><sub><b>Kisaragi</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=KisaragiEffective" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Kallu-A"><img src="https://avatars.githubusercontent.com/u/73198738?v=4?s=100" width="100px;" alt="Lucas Aries"/><br /><sub><b>Lucas Aries</b></sub></a><br /><a href="#content-Kallu-A" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ragreenburg"><img src="https://avatars.githubusercontent.com/u/24358100?v=4?s=100" width="100px;" alt="ragreenburg"/><br /><sub><b>ragreenburg</b></sub></a><br /><a href="#content-ragreenburg" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/stevenfukase"><img src="https://avatars.githubusercontent.com/u/66785624?v=4?s=100" width="100px;" alt="stevenfukase"/><br /><sub><b>stevenfukase</b></sub></a><br /><a href="#content-stevenfukase" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/J-S-Kim"><img src="https://avatars.githubusercontent.com/u/17569303?v=4?s=100" width="100px;" alt="J-S-Kim"/><br /><sub><b>J-S-Kim</b></sub></a><br /><a href="#content-J-S-Kim" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Fointard"><img src="https://avatars.githubusercontent.com/u/9333398?v=4?s=100" width="100px;" alt="Fointard"/><br /><sub><b>Fointard</b></sub></a><br /><a href="#content-Fointard" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/rytheo"><img src="https://avatars.githubusercontent.com/u/22184325?v=4?s=100" width="100px;" alt="Ryan Lowe"/><br /><sub><b>Ryan Lowe</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=rytheo" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://www.dashen.tech"><img src="https://avatars.githubusercontent.com/u/15921519?v=4?s=100" width="100px;" alt="cui fliter"/><br /><sub><b>cui fliter</b></sub></a><br /><a href="#content-cuishuang" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/luskwater"><img src="https://avatars.githubusercontent.com/u/42529?v=4?s=100" width="100px;" alt="Ron Lusk"/><br /><sub><b>Ron Lusk</b></sub></a><br /><a href="#content-luskwater" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://liby.github.io/liby/"><img src="https://avatars.githubusercontent.com/u/38807139?v=4?s=100" width="100px;" alt="Bryan Lee"/><br /><sub><b>Bryan Lee</b></sub></a><br /><a href="#content-liby" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://nandaja.space"><img src="https://avatars.githubusercontent.com/u/2624550?v=4?s=100" width="100px;" alt="Nandaja Varma"/><br /><sub><b>Nandaja Varma</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nandajavarma" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/merelymyself"><img src="https://avatars.githubusercontent.com/u/88221256?v=4?s=100" width="100px;" alt="pwygab"/><br /><sub><b>pwygab</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=merelymyself" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://linkedin.com/in/lucasgrvarela"><img src="https://avatars.githubusercontent.com/u/37870368?v=4?s=100" width="100px;" alt="Lucas Grigolon Varela"/><br /><sub><b>Lucas Grigolon Varela</b></sub></a><br /><a href="#content-lucasgrvarela" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/bufo24"><img src="https://avatars.githubusercontent.com/u/32884105?v=4?s=100" width="100px;" alt="Bufo"/><br /><sub><b>Bufo</b></sub></a><br /><a href="#content-bufo24" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://rustnote.com"><img src="https://avatars.githubusercontent.com/u/77730378?v=4?s=100" width="100px;" alt="Jack Clayton"/><br /><sub><b>Jack Clayton</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jackos" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/klkl0808"><img src="https://avatars.githubusercontent.com/u/24694249?v=4?s=100" width="100px;" alt="Konstantin"/><br /><sub><b>Konstantin</b></sub></a><br /><a href="#content-klkl0808" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/0pling"><img src="https://avatars.githubusercontent.com/u/104090344?v=4?s=100" width="100px;" alt="0pling"/><br /><sub><b>0pling</b></sub></a><br /><a href="#content-0pling" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/KatanaFluorescent"><img src="https://avatars.githubusercontent.com/u/60199077?v=4?s=100" width="100px;" alt="KatanaFluorescent"/><br /><sub><b>KatanaFluorescent</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=KatanaFluorescent" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Drew-Morris"><img src="https://avatars.githubusercontent.com/u/95818166?v=4?s=100" width="100px;" alt="Drew Morris"/><br /><sub><b>Drew Morris</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Drew-Morris" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/camperdue42"><img src="https://avatars.githubusercontent.com/u/43047763?v=4?s=100" width="100px;" alt="camperdue42"/><br /><sub><b>camperdue42</b></sub></a><br /><a href="#content-camperdue42" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/YsuOS"><img src="https://avatars.githubusercontent.com/u/30138661?v=4?s=100" width="100px;" alt="YsuOS"/><br /><sub><b>YsuOS</b></sub></a><br /><a href="#content-YsuOS" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://lichess.org/@/StevenEmily"><img src="https://avatars.githubusercontent.com/u/58114641?v=4?s=100" width="100px;" alt="Steven Nguyen"/><br /><sub><b>Steven Nguyen</b></sub></a><br /><a href="#content-icecream17" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://noahcairns.dev"><img src="https://avatars.githubusercontent.com/u/94420090?v=4?s=100" width="100px;" alt="nacairns1"/><br /><sub><b>nacairns1</b></sub></a><br /><a href="#content-nacairns1" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/pgjbz"><img src="https://avatars.githubusercontent.com/u/22059237?v=4?s=100" width="100px;" alt="Paulo Gabriel Justino Bezerra"/><br /><sub><b>Paulo Gabriel Justino Bezerra</b></sub></a><br /><a href="#content-pgjbz" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jaystile"><img src="https://avatars.githubusercontent.com/u/46078028?v=4?s=100" width="100px;" alt="Jason"/><br /><sub><b>Jason</b></sub></a><br /><a href="#content-jaystile" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://exdx.github.io"><img src="https://avatars.githubusercontent.com/u/31546601?v=4?s=100" width="100px;" alt="exdx"/><br /><sub><b>exdx</b></sub></a><br /><a href="#content-exdx" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Jzow"><img src="https://avatars.githubusercontent.com/u/68860495?v=4?s=100" width="100px;" alt="James Zow"/><br /><sub><b>James Zow</b></sub></a><br /><a href="#content-Jzow" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://jamesabromley.wordpress.com/"><img src="https://avatars.githubusercontent.com/u/2474334?v=4?s=100" width="100px;" alt="James Bromley"/><br /><sub><b>James Bromley</b></sub></a><br /><a href="#content-jayber" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/swhiteCQC"><img src="https://avatars.githubusercontent.com/u/77438466?v=4?s=100" width="100px;" alt="swhiteCQC"/><br /><sub><b>swhiteCQC</b></sub></a><br /><a href="#content-swhiteCQC" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/neilpate"><img src="https://avatars.githubusercontent.com/u/7802334?v=4?s=100" width="100px;" alt="Neil Pate"/><br /><sub><b>Neil Pate</b></sub></a><br /><a href="#content-neilpate" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://wojexe.com"><img src="https://avatars.githubusercontent.com/u/21208490?v=4?s=100" width="100px;" alt="wojexe"/><br /><sub><b>wojexe</b></sub></a><br /><a href="#content-wojexe" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Tostapunk"><img src="https://avatars.githubusercontent.com/u/25140297?v=4?s=100" width="100px;" alt="Mattia Schiavon"/><br /><sub><b>Mattia Schiavon</b></sub></a><br /><a href="#content-Tostapunk" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://toucantoco.com"><img src="https://avatars.githubusercontent.com/u/18406791?v=4?s=100" width="100px;" alt="Eric Jolibois"/><br /><sub><b>Eric Jolibois</b></sub></a><br /><a href="#content-PrettyWood" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://edwinchang.vercel.app"><img src="https://avatars.githubusercontent.com/u/88263098?v=4?s=100" width="100px;" alt="Edwin Chang"/><br /><sub><b>Edwin Chang</b></sub></a><br /><a href="#content-EdwinChang24" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://saikat.dev/"><img src="https://avatars.githubusercontent.com/u/7412443?v=4?s=100" width="100px;" alt="Saikat Das"/><br /><sub><b>Saikat Das</b></sub></a><br /><a href="#content-saikatdas0790" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/thatlittleboy"><img src="https://avatars.githubusercontent.com/u/30731072?v=4?s=100" width="100px;" alt="Jeremy Goh"/><br /><sub><b>Jeremy Goh</b></sub></a><br /><a href="#content-thatlittleboy" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Lioness100"><img src="https://avatars.githubusercontent.com/u/65814829?v=4?s=100" width="100px;" alt="Lioness100"/><br /><sub><b>Lioness100</b></sub></a><br /><a href="#content-Lioness100" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tvkn"><img src="https://avatars.githubusercontent.com/u/79277926?v=4?s=100" width="100px;" alt="Tristan Nicholls"/><br /><sub><b>Tristan Nicholls</b></sub></a><br /><a href="#content-tvkn" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://clairewang.net"><img src="https://avatars.githubusercontent.com/u/9344258?v=4?s=100" width="100px;" alt="Claire"/><br /><sub><b>Claire</b></sub></a><br /><a href="#content-clairew" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Mouwrice"><img src="https://avatars.githubusercontent.com/u/56763273?v=4?s=100" width="100px;" alt="Maurice Van Wassenhove"/><br /><sub><b>Maurice Van Wassenhove</b></sub></a><br /><a href="#content-Mouwrice" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://jmthree.com"><img src="https://avatars.githubusercontent.com/u/77524?v=4?s=100" width="100px;" alt="John Mendelewski"/><br /><sub><b>John Mendelewski</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=johnmendel" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://fakhoury.xyz"><img src="https://avatars.githubusercontent.com/u/20828724?v=4?s=100" width="100px;" alt="Brian Fakhoury"/><br /><sub><b>Brian Fakhoury</b></sub></a><br /><a href="#content-brianfakhoury" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/markusboehme"><img src="https://avatars.githubusercontent.com/u/5074759?v=4?s=100" width="100px;" alt="Markus Boehme"/><br /><sub><b>Markus Boehme</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=markusboehme" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/nico-vromans"><img src="https://avatars.githubusercontent.com/u/48183857?v=4?s=100" width="100px;" alt="Nico Vromans"/><br /><sub><b>Nico Vromans</b></sub></a><br /><a href="#content-nico-vromans" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/vostok92"><img src="https://avatars.githubusercontent.com/u/540339?v=4?s=100" width="100px;" alt="vostok92"/><br /><sub><b>vostok92</b></sub></a><br /><a href="#content-vostok92" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://magnusrodseth.vercel.app"><img src="https://avatars.githubusercontent.com/u/59113973?v=4?s=100" width="100px;" alt="Magnus Rødseth"/><br /><sub><b>Magnus Rødseth</b></sub></a><br /><a href="#content-magnusrodseth" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/rubiesonthesky"><img src="https://avatars.githubusercontent.com/u/2591240?v=4?s=100" width="100px;" alt="rubiesonthesky"/><br /><sub><b>rubiesonthesky</b></sub></a><br /><a href="#content-rubiesonthesky" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://www.gabrielbianconi.com/"><img src="https://avatars.githubusercontent.com/u/1275491?v=4?s=100" width="100px;" alt="Gabriel Bianconi"/><br /><sub><b>Gabriel Bianconi</b></sub></a><br /><a href="#content-GabrielBianconi" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Kodylow"><img src="https://avatars.githubusercontent.com/u/74332828?v=4?s=100" width="100px;" alt="Kody Low"/><br /><sub><b>Kody Low</b></sub></a><br /><a href="#content-Kodylow" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/rzrymiak"><img src="https://avatars.githubusercontent.com/u/106121613?v=4?s=100" width="100px;" alt="rzrymiak"/><br /><sub><b>rzrymiak</b></sub></a><br /><a href="#content-rzrymiak" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/miguelraz"><img src="https://avatars.githubusercontent.com/u/13056181?v=4?s=100" width="100px;" alt="Miguel Raz Guzmán Macedo"/><br /><sub><b>Miguel Raz Guzmán Macedo</b></sub></a><br /><a href="#content-miguelraz" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/memark"><img src="https://avatars.githubusercontent.com/u/318504?v=4?s=100" width="100px;" alt="Magnus Markling"/><br /><sub><b>Magnus Markling</b></sub></a><br /><a href="#content-memark" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/gasparitiago"><img src="https://avatars.githubusercontent.com/u/3237254?v=4?s=100" width="100px;" alt="Tiago De Gaspari"/><br /><sub><b>Tiago De Gaspari</b></sub></a><br /><a href="#content-gasparitiago" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/skaunov"><img src="https://avatars.githubusercontent.com/u/65976143?v=4?s=100" width="100px;" alt="skaunov"/><br /><sub><b>skaunov</b></sub></a><br /><a href="#content-skaunov" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://caljacobson.dev"><img src="https://avatars.githubusercontent.com/u/9152032?v=4?s=100" width="100px;" alt="Cal Jacobson"/><br /><sub><b>Cal Jacobson</b></sub></a><br /><a href="#content-cj81499" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/duchonic"><img src="https://avatars.githubusercontent.com/u/34117620?v=4?s=100" width="100px;" alt="Duchoud Nicolas"/><br /><sub><b>Duchoud Nicolas</b></sub></a><br /><a href="#content-duchonic" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/gfaugere"><img src="https://avatars.githubusercontent.com/u/11901979?v=4?s=100" width="100px;" alt="Gaëtan Faugère"/><br /><sub><b>Gaëtan Faugère</b></sub></a><br /><a href="#tool-gfaugere" title="Tools">🔧</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/bhbuehler"><img src="https://avatars.githubusercontent.com/u/25541343?v=4?s=100" width="100px;" alt="bhbuehler"/><br /><sub><b>bhbuehler</b></sub></a><br /><a href="#content-bhbuehler" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/nyurik"><img src="https://avatars.githubusercontent.com/u/1641515?v=4?s=100" width="100px;" alt="Yuri Astrakhan"/><br /><sub><b>Yuri Astrakhan</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nyurik" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://azzamsa.com"><img src="https://avatars.githubusercontent.com/u/17734314?v=4?s=100" width="100px;" alt="azzamsa"/><br /><sub><b>azzamsa</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=azzamsa" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mvanschellebeeck"><img src="https://avatars.githubusercontent.com/u/17671052?v=4?s=100" width="100px;" alt="mvanschellebeeck"/><br /><sub><b>mvanschellebeeck</b></sub></a><br /><a href="#content-mvanschellebeeck" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/aaarkid"><img src="https://avatars.githubusercontent.com/u/39987510?v=4?s=100" width="100px;" alt="Arkid"/><br /><sub><b>Arkid</b></sub></a><br /><a href="#content-aaarkid" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://tfpk.dev"><img src="https://avatars.githubusercontent.com/u/10906982?v=4?s=100" width="100px;" alt="Tom Kunc"/><br /><sub><b>Tom Kunc</b></sub></a><br /><a href="#content-tfpk" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mfurak"><img src="https://avatars.githubusercontent.com/u/38523093?v=4?s=100" width="100px;" alt="Marek Furák"/><br /><sub><b>Marek Furák</b></sub></a><br /><a href="#content-mfurak" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://winter.cafe"><img src="https://avatars.githubusercontent.com/u/78392041?v=4?s=100" width="100px;" alt="Winter"/><br /><sub><b>Winter</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=winterqt" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://moritzboeh.me"><img src="https://avatars.githubusercontent.com/u/42215704?v=4?s=100" width="100px;" alt="Moritz Böhme"/><br /><sub><b>Moritz Böhme</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=MoritzBoehme" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/craymel"><img src="https://avatars.githubusercontent.com/u/71062756?v=4?s=100" width="100px;" alt="craymel"/><br /><sub><b>craymel</b></sub></a><br /><a href="#content-craymel" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tkburis"><img src="https://avatars.githubusercontent.com/u/20501289?v=4?s=100" width="100px;" alt="TK Buristrakul"/><br /><sub><b>TK Buristrakul</b></sub></a><br /><a href="#content-tkburis" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/HerschelW"><img src="https://avatars.githubusercontent.com/u/17935816?v=4?s=100" width="100px;" alt="Kent Worthington"/><br /><sub><b>Kent Worthington</b></sub></a><br /><a href="#content-HerschelW" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/seporterfield"><img src="https://avatars.githubusercontent.com/u/107010978?v=4?s=100" width="100px;" alt="seporterfield"/><br /><sub><b>seporterfield</b></sub></a><br /><a href="#content-seporterfield" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/dbarrosop"><img src="https://avatars.githubusercontent.com/u/6246622?v=4?s=100" width="100px;" alt="David Barroso"/><br /><sub><b>David Barroso</b></sub></a><br /><a href="#infra-dbarrosop" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://distanz.ch"><img src="https://avatars.githubusercontent.com/u/539708?v=4?s=100" width="100px;" alt="Tobias Klauser"/><br /><sub><b>Tobias Klauser</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=tklauser" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/0xMySt1c"><img src="https://avatars.githubusercontent.com/u/101825630?v=4?s=100" width="100px;" alt="0xMySt1c"/><br /><sub><b>0xMySt1c</b></sub></a><br /><a href="#tool-0xMySt1c" title="Tools">🔧</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/AxolotlTears"><img src="https://avatars.githubusercontent.com/u/87157047?v=4?s=100" width="100px;" alt="Ten"/><br /><sub><b>Ten</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=AxolotlTears" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://h4x5p4c3.xyz"><img src="https://avatars.githubusercontent.com/u/66133688?v=4?s=100" width="100px;" alt="jones martin"/><br /><sub><b>jones martin</b></sub></a><br /><a href="#content-h4x5p4c3" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/cloppingemu"><img src="https://avatars.githubusercontent.com/u/12227963?v=4?s=100" width="100px;" alt="cloppingemu"/><br /><sub><b>cloppingemu</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cloppingemu" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://github.com/zeromicro/go-zero"><img src="https://avatars.githubusercontent.com/u/1918356?v=4?s=100" width="100px;" alt="Kevin Wan"/><br /><sub><b>Kevin Wan</b></sub></a><br /><a href="#content-kevwan" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://kurowasaruby.cn"><img src="https://avatars.githubusercontent.com/u/43495006?v=4?s=100" width="100px;" alt="Ruby"/><br /><sub><b>Ruby</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=wjwrh" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/alexandergill"><img src="https://avatars.githubusercontent.com/u/7033716?v=4?s=100" width="100px;" alt="Alexander Gill"/><br /><sub><b>Alexander Gill</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=alexandergill" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/jarrod-sanders/"><img src="https://avatars.githubusercontent.com/u/50600614?v=4?s=100" width="100px;" alt="Jarrod Sanders"/><br /><sub><b>Jarrod Sanders</b></sub></a><br /><a href="#content-kawaiiPlat" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/platformer"><img src="https://avatars.githubusercontent.com/u/40146328?v=4?s=100" width="100px;" alt="Andrew Sen"/><br /><sub><b>Andrew Sen</b></sub></a><br /><a href="#content-platformer" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://grzegorz-zur.com/"><img src="https://avatars.githubusercontent.com/u/5297583?v=4?s=100" width="100px;" alt="Grzegorz Żur"/><br /><sub><b>Grzegorz Żur</b></sub></a><br /><a href="#content-grzegorz-zur" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/black-puppydog"><img src="https://avatars.githubusercontent.com/u/189241?v=4?s=100" width="100px;" alt="Daan Wynen"/><br /><sub><b>Daan Wynen</b></sub></a><br /><a href="#content-black-puppydog" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Anush008"><img src="https://avatars.githubusercontent.com/u/46051506?v=4?s=100" width="100px;" alt="Anush"/><br /><sub><b>Anush</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Anush008" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/shgew"><img src="https://avatars.githubusercontent.com/u/5584672?v=4?s=100" width="100px;" alt="Gleb Shevchenko"/><br /><sub><b>Gleb Shevchenko</b></sub></a><br /><a href="#content-shgew" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mdmundo"><img src="https://avatars.githubusercontent.com/u/60408300?v=4?s=100" width="100px;" alt="Edmundo Paulino"/><br /><sub><b>Edmundo Paulino</b></sub></a><br /><a href="#infra-mdmundo" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/eroullit"><img src="https://avatars.githubusercontent.com/u/301795?v=4?s=100" width="100px;" alt="Emmanuel Roullit"/><br /><sub><b>Emmanuel Roullit</b></sub></a><br /><a href="#infra-eroullit" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://nidhalmessaoudi.herokuapp.com"><img src="https://avatars.githubusercontent.com/u/63377412?v=4?s=100" width="100px;" alt="Nidhal Messaoudi"/><br /><sub><b>Nidhal Messaoudi</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nidhalmessaoudi" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/MahdiBM"><img src="https://avatars.githubusercontent.com/u/54685446?v=4?s=100" width="100px;" alt="Mahdi Bahrami"/><br /><sub><b>Mahdi Bahrami</b></sub></a><br /><a href="#tool-MahdiBM" title="Tools">🔧</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Nagidal"><img src="https://avatars.githubusercontent.com/u/7075397?v=4?s=100" width="100px;" alt="Nagidal"/><br /><sub><b>Nagidal</b></sub></a><br /><a href="#content-Nagidal" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://adabrew.com"><img src="https://avatars.githubusercontent.com/u/25161597?v=4?s=100" width="100px;" alt="Adam Brewer"/><br /><sub><b>Adam Brewer</b></sub></a><br /><a href="#content-adamhb123" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/eugkhp"><img src="https://avatars.githubusercontent.com/u/25910599?v=4?s=100" width="100px;" alt="Eugene"/><br /><sub><b>Eugene</b></sub></a><br /><a href="#tool-eugkhp" title="Tools">🔧</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://social.linux.pizza/@navicore"><img src="https://avatars.githubusercontent.com/u/110999?v=4?s=100" width="100px;" alt="Ed Sweeney"/><br /><sub><b>Ed Sweeney</b></sub></a><br /><a href="#content-navicore" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/javihernant"><img src="https://avatars.githubusercontent.com/u/73640929?v=4?s=100" width="100px;" alt="javihernant"/><br /><sub><b>javihernant</b></sub></a><br /><a href="#content-javihernant" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/VegardMatthey"><img src="https://avatars.githubusercontent.com/u/59250656?v=4?s=100" width="100px;" alt="Vegard"/><br /><sub><b>Vegard</b></sub></a><br /><a href="#content-VegardMatthey" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ryanwhitehouse"><img src="https://avatars.githubusercontent.com/u/13400784?v=4?s=100" width="100px;" alt="Ryan Whitehouse"/><br /><sub><b>Ryan Whitehouse</b></sub></a><br /><a href="#content-ryanwhitehouse" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/guoard"><img src="https://avatars.githubusercontent.com/u/65511355?v=4?s=100" width="100px;" alt="Ali Afsharzadeh"/><br /><sub><b>Ali Afsharzadeh</b></sub></a><br /><a href="#content-guoard" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://keogami.ml"><img src="https://avatars.githubusercontent.com/u/41939011?v=4?s=100" width="100px;" alt="Keogami"/><br /><sub><b>Keogami</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=keogami" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ahresse"><img src="https://avatars.githubusercontent.com/u/28402488?v=4?s=100" width="100px;" alt="Alexandre Esse"/><br /><sub><b>Alexandre Esse</b></sub></a><br /><a href="#content-ahresse" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://resilient.tech"><img src="https://avatars.githubusercontent.com/u/16315650?v=4?s=100" width="100px;" alt="Sagar Vora"/><br /><sub><b>Sagar Vora</b></sub></a><br /><a href="#content-sagarvora" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/poneciak57"><img src="https://avatars.githubusercontent.com/u/94321164?v=4?s=100" width="100px;" alt="Kacper Poneta"/><br /><sub><b>Kacper Poneta</b></sub></a><br /><a href="#content-poneciak57" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://ktheory.com/"><img src="https://avatars.githubusercontent.com/u/975?v=4?s=100" width="100px;" alt="Aaron Suggs"/><br /><sub><b>Aaron Suggs</b></sub></a><br /><a href="#content-ktheory" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/alexwh"><img src="https://avatars.githubusercontent.com/u/1723612?v=4?s=100" width="100px;" alt="Alex"/><br /><sub><b>Alex</b></sub></a><br /><a href="#content-alexwh" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/stornquist"><img src="https://avatars.githubusercontent.com/u/42915664?v=4?s=100" width="100px;" alt="Sebastian Törnquist"/><br /><sub><b>Sebastian Törnquist</b></sub></a><br /><a href="#content-stornquist" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://smlavine.com"><img src="https://avatars.githubusercontent.com/u/33563640?v=4?s=100" width="100px;" alt="Sebastian LaVine"/><br /><sub><b>Sebastian LaVine</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=smlavine" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="http://www.alangerber.us"><img src="https://avatars.githubusercontent.com/u/201313?v=4?s=100" width="100px;" alt="Alan Gerber"/><br /><sub><b>Alan Gerber</b></sub></a><br /><a href="#content-akgerber" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://esotuvaka.github.io"><img src="https://avatars.githubusercontent.com/u/104941850?v=4?s=100" width="100px;" alt="Eric"/><br /><sub><b>Eric</b></sub></a><br /><a href="#content-esotuvaka" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/az0977776"><img src="https://avatars.githubusercontent.com/u/9172038?v=4?s=100" width="100px;" alt="Aaron Wang"/><br /><sub><b>Aaron Wang</b></sub></a><br /><a href="#content-az0977776" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/nmay231"><img src="https://avatars.githubusercontent.com/u/35386821?v=4?s=100" width="100px;" alt="Noah"/><br /><sub><b>Noah</b></sub></a><br /><a href="#content-nmay231" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/rb5014"><img src="https://avatars.githubusercontent.com/u/105397317?v=4?s=100" width="100px;" alt="rb5014"/><br /><sub><b>rb5014</b></sub></a><br /><a href="#content-rb5014" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/deedy5"><img src="https://avatars.githubusercontent.com/u/65482418?v=4?s=100" width="100px;" alt="deedy5"/><br /><sub><b>deedy5</b></sub></a><br /><a href="#content-deedy5" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/lionel-rowe"><img src="https://avatars.githubusercontent.com/u/26078826?v=4?s=100" width="100px;" alt="lionel-rowe"/><br /><sub><b>lionel-rowe</b></sub></a><br /><a href="#content-lionel-rowe" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Ben2917"><img src="https://avatars.githubusercontent.com/u/10279994?v=4?s=100" width="100px;" alt="Ben"/><br /><sub><b>Ben</b></sub></a><br /><a href="#content-Ben2917" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/b1ue64"><img src="https://avatars.githubusercontent.com/u/77976308?v=4?s=100" width="100px;" alt="b1ue64"/><br /><sub><b>b1ue64</b></sub></a><br /><a href="#content-b1ue64" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/lazywalker"><img src="https://avatars.githubusercontent.com/u/53956?v=4?s=100" width="100px;" alt="lazywalker"/><br /><sub><b>lazywalker</b></sub></a><br /><a href="#content-lazywalker" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/proofconstruction"><img src="https://avatars.githubusercontent.com/u/74747193?v=4?s=100" width="100px;" alt="proofconstruction"/><br /><sub><b>proofconstruction</b></sub></a><br /><a href="#infra-proofconstruction" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.youtube.com/channel/UCQCjA6qUutAtWqkCA4Z36CQ"><img src="https://avatars.githubusercontent.com/u/16007179?v=4?s=100" width="100px;" alt="IVIURRAY"/><br /><sub><b>IVIURRAY</b></sub></a><br /><a href="#content-IVIURRAY" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/b-apperlo"><img src="https://avatars.githubusercontent.com/u/91734527?v=4?s=100" width="100px;" alt="Bert Apperlo"/><br /><sub><b>Bert Apperlo</b></sub></a><br /><a href="#content-b-apperlo" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://fwdekker.com/"><img src="https://avatars.githubusercontent.com/u/13442533?v=4?s=100" width="100px;" alt="Florine W. Dekker"/><br /><sub><b>Florine W. Dekker</b></sub></a><br /><a href="#content-FWDekker" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/luhem7"><img src="https://avatars.githubusercontent.com/u/4008215?v=4?s=100" width="100px;" alt="Mehul Gangavelli"/><br /><sub><b>Mehul Gangavelli</b></sub></a><br /><a href="#content-luhem7" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Frosthage"><img src="https://avatars.githubusercontent.com/u/14823314?v=4?s=100" width="100px;" alt="Mikael Frosthage"/><br /><sub><b>Mikael Frosthage</b></sub></a><br /><a href="#content-Frosthage" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://robertfry.xyz"><img src="https://avatars.githubusercontent.com/u/43712054?v=4?s=100" width="100px;" alt="Robert Fry"/><br /><sub><b>Robert Fry</b></sub></a><br /><a href="#content-robertefry" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/tajo48"><img src="https://avatars.githubusercontent.com/u/55502906?v=4?s=100" width="100px;" alt="tajo48"/><br /><sub><b>tajo48</b></sub></a><br /><a href="#content-tajo48" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://anishchhetri.com.np"><img src="https://avatars.githubusercontent.com/u/98446102?v=4?s=100" width="100px;" alt="Anish"/><br /><sub><b>Anish</b></sub></a><br /><a href="#content-novanish" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/vnprc"><img src="https://avatars.githubusercontent.com/u/9425366?v=4?s=100" width="100px;" alt="vnprc"/><br /><sub><b>vnprc</b></sub></a><br /><a href="#content-vnprc" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://androecia.net"><img src="https://avatars.githubusercontent.com/u/61999256?v=4?s=100" width="100px;" alt="Joshua Carlson"/><br /><sub><b>Joshua Carlson</b></sub></a><br /><a href="#content-jrcarl624" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://johndesilencio.me"><img src="https://avatars.githubusercontent.com/u/20136554?v=4?s=100" width="100px;" alt="Nicholas R. Smith"/><br /><sub><b>Nicholas R. Smith</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=johnDeSilencio" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://alexfertel.me"><img src="https://avatars.githubusercontent.com/u/22298999?v=4?s=100" width="100px;" alt="Alexander González"/><br /><sub><b>Alexander González</b></sub></a><br /><a href="#content-alexfertel" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/softarn"><img src="https://avatars.githubusercontent.com/u/517619?v=4?s=100" width="100px;" alt="Marcus Höjvall"/><br /><sub><b>Marcus Höjvall</b></sub></a><br /><a href="#content-softarn" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/barlevalon"><img src="https://avatars.githubusercontent.com/u/3397911?v=4?s=100" width="100px;" alt="Alon Hearter"/><br /><sub><b>Alon Hearter</b></sub></a><br /><a href="#content-barlevalon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/shirts"><img src="https://avatars.githubusercontent.com/u/4952151?v=4?s=100" width="100px;" alt="shirts"/><br /><sub><b>shirts</b></sub></a><br /><a href="#content-shirts" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/eLVas"><img src="https://avatars.githubusercontent.com/u/6797156?v=4?s=100" width="100px;" alt="Ivan Vasiunyk"/><br /><sub><b>Ivan Vasiunyk</b></sub></a><br /><a href="#content-eLVas" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://mo8it.com"><img src="https://avatars.githubusercontent.com/u/76752051?v=4?s=100" width="100px;" alt="Mo"/><br /><sub><b>Mo</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=mo8it" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/x10an14"><img src="https://avatars.githubusercontent.com/u/710608?v=4?s=100" width="100px;" alt="x10an14"/><br /><sub><b>x10an14</b></sub></a><br /><a href="#infra-x10an14" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/gabay"><img src="https://avatars.githubusercontent.com/u/5773610?v=4?s=100" width="100px;" alt="Roi Gabay"/><br /><sub><b>Roi Gabay</b></sub></a><br /><a href="#content-gabay" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/mkovaxx"><img src="https://avatars.githubusercontent.com/u/481354?v=4?s=100" width="100px;" alt="Máté Kovács"/><br /><sub><b>Máté Kovács</b></sub></a><br /><a href="#content-mkovaxx" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://szabgab.com/"><img src="https://avatars.githubusercontent.com/u/48833?v=4?s=100" width="100px;" alt="Gábor Szabó"/><br /><sub><b>Gábor Szabó</b></sub></a><br /><a href="#content-szabgab" title="Content">🖋</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://moduslaborandi.net"><img src="https://avatars.githubusercontent.com/u/3340793?v=4?s=100" width="100px;" alt="Yamila Moreno"/><br /><sub><b>Yamila Moreno</b></sub></a><br /><a href="#content-yamila-moreno" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/willhack"><img src="https://avatars.githubusercontent.com/u/18036720?v=4?s=100" width="100px;" alt="Will Hack"/><br /><sub><b>Will Hack</b></sub></a><br /><a href="#content-willhack" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://cancompute.tech"><img src="https://avatars.githubusercontent.com/u/2052646?v=4?s=100" width="100px;" alt="Michael"/><br /><sub><b>Michael</b></sub></a><br /><a href="#content-bean5" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.sadiqpk.org"><img src="https://avatars.githubusercontent.com/u/1289514?v=4?s=100" width="100px;" alt="Mohammed Sadiq"/><br /><sub><b>Mohammed Sadiq</b></sub></a><br /><a href="#content-pksadiq" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Jak-Ch-ll"><img src="https://avatars.githubusercontent.com/u/56225668?v=4?s=100" width="100px;" alt="Jakob"/><br /><sub><b>Jakob</b></sub></a><br /><a href="#content-Jak-Ch-ll" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://oscarbonilla.com"><img src="https://avatars.githubusercontent.com/u/4950?v=4?s=100" width="100px;" alt="Oscar Bonilla"/><br /><sub><b>Oscar Bonilla</b></sub></a><br /><a href="#content-ob" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/husjon"><img src="https://avatars.githubusercontent.com/u/554229?v=4?s=100" width="100px;" alt="Jon Erling Hustadnes"/><br /><sub><b>Jon Erling Hustadnes</b></sub></a><br /><a href="#content-husjon" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/CobaltCause"><img src="https://avatars.githubusercontent.com/u/7003738?v=4?s=100" width="100px;" alt="Charles Hall"/><br /><sub><b>Charles Hall</b></sub></a><br /><a href="#infra-CobaltCause" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/krmpotic"><img src="https://avatars.githubusercontent.com/u/10350645?v=4?s=100" width="100px;" alt="Luka Krmpotić"/><br /><sub><b>Luka Krmpotić</b></sub></a><br /><a href="#content-krmpotic" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/jurglic"><img src="https://avatars.githubusercontent.com/u/112600?v=4?s=100" width="100px;" alt="Jurglic"/><br /><sub><b>Jurglic</b></sub></a><br /><a href="#content-jurglic" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/OfirLauber"><img src="https://avatars.githubusercontent.com/u/5631030?v=4?s=100" width="100px;" alt="Ofir Lauber"/><br /><sub><b>Ofir Lauber</b></sub></a><br /><a href="#content-OfirLauber" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/offbyone"><img src="https://avatars.githubusercontent.com/u/181693?v=4?s=100" width="100px;" alt="Chris Rose"/><br /><sub><b>Chris Rose</b></sub></a><br /><a href="#infra-offbyone" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/dieterplex"><img src="https://avatars.githubusercontent.com/u/507502?v=4?s=100" width="100px;" alt="d1t2"/><br /><sub><b>d1t2</b></sub></a><br /><a href="#infra-dieterplex" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/docwilco"><img src="https://avatars.githubusercontent.com/u/66911096?v=4?s=100" width="100px;" alt="docwilco"/><br /><sub><b>docwilco</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=docwilco" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/matthew-nield1/"><img src="https://avatars.githubusercontent.com/u/64328730?v=4?s=100" width="100px;" alt="Matt Nield"/><br /><sub><b>Matt Nield</b></sub></a><br /><a href="#content-matthewjnield" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/TheBearodactyl"><img src="https://avatars.githubusercontent.com/u/114454115?v=4?s=100" width="100px;" alt="The Bearodactyl"/><br /><sub><b>The Bearodactyl</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=TheBearodactyl" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/markgreene74"><img src="https://avatars.githubusercontent.com/u/18945890?v=4?s=100" width="100px;" alt="markgreene74"/><br /><sub><b>markgreene74</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=markgreene74" title="Code">💻</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/VeeDeltaVee"><img src="https://avatars.githubusercontent.com/u/45564258?v=4?s=100" width="100px;" alt="Versha Dhankar"/><br /><sub><b>Versha Dhankar</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=VeeDeltaVee" title="Documentation">📖</a></td>
<td align="center" valign="top" width="12.5%"><a href="http://0atman.com"><img src="https://avatars.githubusercontent.com/u/114097?v=4?s=100" width="100px;" alt="Tristram Oaten"/><br /><sub><b>Tristram Oaten</b></sub></a><br /><a href="#content-0atman" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/danieltinazzi"><img src="https://avatars.githubusercontent.com/u/11833533?v=4?s=100" width="100px;" alt="Daniel Tinazzi"/><br /><sub><b>Daniel Tinazzi</b></sub></a><br /><a href="#content-danieltinazzi" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://github.com/raymon-roos"><img src="https://avatars.githubusercontent.com/u/38888470?v=4?s=100" width="100px;" alt="Raymon Roos"/><br /><sub><b>Raymon Roos</b></sub></a><br /><a href="#content-raymon-roos" title="Content">🖋</a></td>
<td align="center" valign="top" width="12.5%"><a href="https://codecrafters.io"><img src="https://avatars.githubusercontent.com/u/3149580?v=4?s=100" width="100px;" alt="Sarup Banskota"/><br /><sub><b>Sarup Banskota</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sarupbanskota" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

View file

@ -1,4 +1,79 @@
<a name="6.0.1"></a>
## 6.0.1 (2024-07-04)
Small exercise improvements and fixes.
Most importantly, fixed that the exercise `clippy1` was already solved 😅
<a name="6.0.0"></a>
## 6.0.0 (2024-07-03)
This release is the result of a complete rewrite to deliver a ton of new features and improvements ✨
The most important changes are highlighted below.
### Installation
The installation has been simplified a lot!
To install Rustlings after installing Rust, all what you need to do now is running the following command:
```bash
cargo install rustlings
```
Yes, this means that Rustlings is now on [crates.io](https://crates.io/crates/rustlings) 🎉
You can read about the motivations of this change in [this issue](https://github.com/rust-lang/rustlings/issues/1919).
### UI/UX
- The UI is now responsive when the terminal is resized.
- The progress bar was moved to the bottom so that you can always see your progress and the current exercise to work on.
- The current exercise path is now a terminal link. It will open the exercise file in your default editor when you click on it.
- A small prompt is now always shown at the bottom. It allows you to choose an action by entering a character. For example, entering `h` will show you the hint of the current exercise.
- The comment "I AM NOT DONE!" doesn't exist anymore. Instead of needing to remove it to go to the next exercise, you need to enter `n` in the terminal.
### List mode
A list mode was added using [Ratatui](https://ratatui.rs).
You can enter it by entering `l` in the watch mode.
It offers the following features:
- Browse all exercises and see their state (pending/done).
- Filter exercises based on their state (pending/done).
- Continue at another exercise. This allows you to skip some exercises or go back to previous ones.
- Reset an exercise so you can start over and revert your changes.
### Solutions
After finishing an exercise, a solution file will be available and Rustlings will show you its path in green.
This allows you to compare your solution with an idiomatic solution and maybe learn about other ways to solve a problem.
While writing the solutions, all exercises have been polished 🌟
For example, every exercise now contains `TODO` comments to highlight what the user needs to change and where.
### LSP support out of the box
Instead of creating a `project.json` file using `rustlings lsp`, Rustlings now works with a `Cargo.toml` file out of the box.
No actions are needed to activate the language server `rust-analyzer`.
This should avoid issues related to the language server or to running exercises, especially the ones with Clippy.
### Clippy
Clippy lints are now shown on all exercises, not only the Clippy exercises 📎
Make Clippy your friend from early on 🥰
### Third party exercises
Rustlings now supports third-party exercises!
Do you want to create your own set of Rustlings exercises to focus on some specific topic?
Or do you want to translate the original Rustlings exercises?
Then follow the link to the guide about [third-party exercises](THIRD_PARTY_EXERCISES.md)!
<a name="5.6.1"></a> <a name="5.6.1"></a>
## 5.6.1 (2023-09-18) ## 5.6.1 (2023-09-18)
#### Changed #### Changed
@ -15,6 +90,7 @@
- `enums3`: Fixed formatting with `rustfmt`. - `enums3`: Fixed formatting with `rustfmt`.
<a name="5.6.0"></a> <a name="5.6.0"></a>
## 5.6.0 (2023-09-04) ## 5.6.0 (2023-09-04)
#### Added #### Added
@ -55,6 +131,7 @@
- Improved CI workflows, we're now testing on multiple platforms at once. - Improved CI workflows, we're now testing on multiple platforms at once.
<a name="5.5.1"></a> <a name="5.5.1"></a>
## 5.5.1 (2023-05-17) ## 5.5.1 (2023-05-17)
#### Fixed #### Fixed
@ -62,6 +139,7 @@
- Reverted `rust-project.json` path generation due to an upstream `rust-analyzer` fix. - Reverted `rust-project.json` path generation due to an upstream `rust-analyzer` fix.
<a name="5.5.0"></a> <a name="5.5.0"></a>
## 5.5.0 (2023-05-17) ## 5.5.0 (2023-05-17)
#### Added #### Added
@ -97,6 +175,7 @@
- Split quick installation section into two code blocks - Split quick installation section into two code blocks
<a name="5.4.1"></a> <a name="5.4.1"></a>
## 5.4.1 (2023-03-10) ## 5.4.1 (2023-03-10)
#### Changed #### Changed
@ -167,7 +246,7 @@
- **structs3**: Clarifed the hint - **structs3**: Clarifed the hint
- **quiz2, as_ref_mut, options1, traits1, traits2**: Clarified hints - **quiz2, as_ref_mut, options1, traits1, traits2**: Clarified hints
- **traits1, traits2, cli**: Tidied up unmatching backticks - **traits1, traits2, cli**: Tidied up unmatching backticks
- **enums2**: Removed unneccessary indirection of self - **enums2**: Removed unnecessary indirection of self
- **enums3**: Added an extra tuple comment - **enums3**: Added an extra tuple comment
#### Housekeeping #### Housekeeping

View file

@ -1,130 +1,61 @@
## Contributing to Rustlings # Contributing to Rustlings
First off, thanks for taking the time to contribute!! ❤️ First off, thanks for taking the time to contribute! ❤️
### Quick Reference ## Quick Reference
I want to... I want to
_add an exercise! ➡️ [read this](#addex) and then [open a Pull Request](#prs)_ - _report a bug!_ ➡️ [open an issue](#issues)
- _fix a bug!_ ➡️ [open a pull request](#pull-requests)
- _implement a new feature!_ ➡️ [open an issue to discuss it first, then a pull request](#issues)
- _add an exercise!_ ➡️ [read this](#adding-an-exercise)
- _update an outdated exercise!_ ➡️ [open a pull request](#pull-requests)
_update an outdated exercise! ➡️ [open a Pull Request](#prs)_ ## Issues
_report a bug! ➡️ [open an Issue](#issues)_
_fix a bug! ➡️ [open a Pull Request](#prs)_
_implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull Request](#issues)_
<a name="#src"></a>
### Working on the source code
`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
isn't really that complicated since the bulk of the work is done by `rustc`.
`src/main.rs` contains a simple `argh` CLI that connects to most of the other source files.
<a name="addex"></a>
### Adding an exercise
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify` and `rustlings watch`.
Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following:
```diff
...
+ [[exercises]]
+ name = "yourTopicN"
+ path = "exercises/yourTopic/yourTopicN.rs"
+ mode = "compile"
+ hint = """
+ Some kind of useful hint for your exercise."""
...
```
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`. If you're working on a Clippy exercise, use `mode = "clippy"`.
That's all! Feel free to put up a pull request.
<a name="issues"></a>
### Issues
You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new). You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new).
If you're reporting a bug, please include the output of the following commands: If you're reporting a bug, please include the output of the following commands:
- `rustc --version` - `cargo --version`
- `rustlings --version` - `rustlings --version`
- `ls -la` - `ls -la`
- Your OS name and version - Your OS name and version
<a name="prs"></a> ## Pull Requests
### Pull Requests
Opening a pull request is as easy as forking the repository and committing your You are welcome to open a pull request, but unless it is small and trivial, **please open an issue to discuss your idea first** 🙏🏼
changes. There's a couple of things to watch out for:
#### Write correct commit messages Opening a pull request is as easy as forking the repository and committing your changes.
If you need any help with it or face any Git related problems, don't hesitate to ask for help 🤗
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) It may take time to review your pull request.
specification. Please be patient 😇
This means that you have to format your commit messages in a specific way. Say
you're working on adding a new exercise called `foobar1.rs`. You could write
the following commit message:
``` When updating an exercise, check if its solution needs to be updated.
feat: add foobar1.rs exercise
## Adding An Exercise
- Name the file `exercises/yourTopic/yourTopicN.rs`.
- Make sure to put in some helpful links, and link to sections of The Book in `exercises/yourTopic/README.md`.
- In the exercise, add a `// TODO: …` comment where user changes are required.
- Add a solution at `solutions/yourTopic/yourTopicN.rs` with comments explaining it.
- Add the [metadata for your exercise](#exercise-metadata) in the `rustlings-macros/info.toml` file.
- Make sure your exercise runs with `rustlings run yourTopicN`.
- [Open a pull request](#pull-requests).
### Exercise Metadata
The exercise metadata should contain the following:
```toml
[[exercises]]
name = "yourTopicN"
dir = "yourTopic"
hint = """
A useful (multi-line) hint for your exercise.
Include links to a section in The Book or a documentation page."""
``` ```
If you're just fixing a bug, please use the `fix` type: If your exercise doesn't contain any test, add `test = false` to the exercise metadata.
But adding tests is recommended.
```
fix(verify): make sure verify doesn't self-destruct
```
The scope within the brackets is optional, but should be any of these:
- `installation` (for the installation script)
- `cli` (for general CLI changes)
- `verify` (for the verification source file)
- `watch` (for the watch functionality source)
- `run` (for the run functionality source)
- `EXERCISENAME` (if you're changing a specific exercise, or set of exercises,
substitute them here)
When the commit also happens to close an existing issue, link it in the message
body:
```
fix: update foobar
closes #101029908
```
If you're doing simple changes, like updating a book link, use `chore`:
```
chore: update exercise1.rs book link
```
If you're updating documentation, use `docs`:
```
docs: add more information to Readme
```
If, and only if, you're absolutely sure you want to make a breaking change
(please discuss this beforehand!), add an exclamation mark to the type and
explain the breaking change in the message body:
```
fix!: completely change verification
BREAKING CHANGE: This has to be done because lorem ipsum dolor
```
#### Pull Request Workflow
Once you open a Pull Request, it may be reviewed or labeled (or both) until
the maintainers accept your change. Please be patient, it may take some time
for this to happen!

897
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,30 +1,72 @@
[workspace]
resolver = "2"
exclude = [
"tests/fixture/failure",
"tests/fixture/state",
"tests/fixture/success",
"dev",
]
[workspace.package]
version = "6.0.1"
authors = [
"Liv <mokou@fastmail.com>",
"Mo Bitar <mo8it@proton.me>",
# Alumni
"Carol (Nichols || Goulding) <carol.nichols@gmail.com>",
]
repository = "https://github.com/rust-lang/rustlings"
license = "MIT"
edition = "2021"
[workspace.dependencies]
serde = { version = "1.0.203", features = ["derive"] }
toml_edit = { version = "0.22.14", default-features = false, features = ["parse", "serde"] }
[package] [package]
name = "rustlings" name = "rustlings"
description = "Small exercises to get you used to reading and writing Rust code!" description = "Small exercises to get you used to reading and writing Rust code!"
version = "5.6.1" version.workspace = true
authors = [ authors.workspace = true
"Liv <mokou@fastmail.com>", repository.workspace = true
"Carol (Nichols || Goulding) <carol.nichols@gmail.com>", license.workspace = true
edition.workspace = true
keywords = [
"exercise",
"learning",
]
include = [
"/src/",
"/exercises/",
"/solutions/",
# A symlink to be able to include `dev/Cargo.toml` although `dev` is excluded.
"/dev-Cargo.toml",
"/README.md",
"/LICENSE",
] ]
edition = "2021"
[dependencies] [dependencies]
indicatif = "0.17.6" anyhow = "1.0.86"
console = "0.15" clap = { version = "4.5.8", features = ["derive"] }
notify = "4.0" crossterm = "0.27.0"
toml = "0.7.6" hashbrown = "0.14.5"
regex = "1.5" notify-debouncer-mini = { version = "0.4.1", default-features = false }
serde = { version = "1.0", features = ["derive"] } os_pipe = "1.2.0"
serde_json = "1.0.81" ratatui = { version = "0.27.0", default-features = false, features = ["crossterm"] }
home = "0.5.3" rustlings-macros = { path = "rustlings-macros", version = "=6.0.1" }
glob = "0.3.0" serde_json = "1.0.120"
clap = { version = "4.4.0", features = ["derive"] } serde.workspace = true
toml_edit.workspace = true
[[bin]]
name = "rustlings"
path = "src/main.rs"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.12" assert_cmd = "2.0.14"
predicates = "3.0.3" predicates = "3.1.0"
glob = "0.3.0"
[profile.release]
panic = "abort"
[profile.dev]
panic = "abort"
[package.metadata.release]
pre-release-hook = ["./release-hook.sh"]

199
README.md
View file

@ -1,182 +1,143 @@
<div class="oranda-hide"> <div class="oranda-hide">
# rustlings 🦀❤️ # Rustlings 🦀❤️
</div> </div>
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! 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!
_...looking for the old, web-based version of Rustlings? Try [here](https://github.com/rust-lang/rustlings/tree/rustlings-1)_ It is recommended to do the Rustlings exercises in parallel to reading [the official Rust book](https://doc.rust-lang.org/book/), the most comprehensive resource for learning Rust 📚️
Alternatively, for a first-time Rust learner, there are several other resources: [Rust By Example](https://doc.rust-lang.org/rust-by-example/) is another recommended resource that you might find helpful.
It contains code examples and exercises similar to Rustlings, but online.
- [The Book](https://doc.rust-lang.org/book/index.html) - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings!
- [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) - Learn Rust by solving little exercises! It's almost like `rustlings`, but online
## Getting Started ## Getting Started
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._ ### Installing Rust
_Note: If you're on Linux, make sure you've installed gcc. Deb: `sudo apt install gcc`. Yum: `sudo yum -y install gcc`._
You will need to have Rust installed. You can get it by visiting <https://rustup.rs>. This'll also install Cargo, Rust's package/project manager. Before installing Rustlings, you need to have _Rust installed_.
Visit [www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) for further instructions on installing Rust.
This'll also install _Cargo_, Rust's package/project manager.
## MacOS/Linux > 🐧 If you're on Linux, make sure you've installed `gcc` (for a linker).
>
> Deb: `sudo apt install gcc`.
> Dnf: `sudo dnf install gcc`.
Just run: > 🍎 If you're on MacOS, make sure you've installed Xcode and its developer tools by running `xcode-select --install`.
### Installing Rustlings
The following command will download and compile Rustlings:
```bash ```bash
curl -L sh.rustlings.cool | bash cargo install rustlings
``` ```
Or if you want it to be installed to a different path: <details>
<summary><strong>If the installation fails…</strong> (<em>click to expand</em>)</summary>
- Make sure you have the latest Rust version by running `rustup update`
- Try adding the `--locked` flag: `cargo install rustlings --locked`
- Otherwise, please [report the issue](https://github.com/rust-lang/rustlings/issues/new)
</details>
### Initialization
After installing Rustlings, run the following command to initialize the `rustlings/` directory:
```bash ```bash
curl -L sh.rustlings.cool | bash -s mypath/ rustlings init
``` ```
This will install Rustlings and give you access to the `rustlings` command. Run it to get started! Now, go into the newly initialized directory and launch Rustlings for further instructions on getting started with the exercises:
### Nix
Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`.
```bash ```bash
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1) cd rustlings/
git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings rustlings
cd rustlings
# if nix version > 2.3
nix develop
# if nix version <= 2.3
nix-shell
``` ```
## Windows ## Working environment
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`: ### Editor
```ps1 Our general recommendation is [VS Code](https://code.visualstudio.com/) with the [rust-analyzer plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser But any editor that supports [rust-analyzer](https://rust-analyzer.github.io/) should be enough for working on the exercises.
```
Then, you can run: ### Terminal
```ps1 While working with Rustlings, please use a modern terminal for the best user experience.
Start-BitsTransfer -Source https://ps1.rustlings.cool -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1 The default terminal on Linux and Mac should be sufficient.
``` On Windows, we recommend the [Windows Terminal](https://aka.ms/terminal).
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it. Keep in mind that this works best in PowerShell, and any other terminals may give you errors. If you use VS Code, the builtin terminal should also be fine.
If you get a permission denied message, you might have to exclude the directory where you cloned Rustlings in your antivirus.
## Browser
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rust-lang/rustlings)
[![Open Rustlings On Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/?repo=rust-lang%2Frustlings&ref=main)
## Manually
Basically: Clone the repository at the latest tag, run `cargo install --path .`.
```bash
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1)
git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings
cd rustlings
cargo install --force --path .
```
If there are installation errors, ensure that your toolchain is up to date. For the latest, run:
```bash
rustup update
```
Then, same as above, run `rustlings` to get started.
## Doing exercises ## Doing exercises
The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/<topic>`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start. The exercises are sorted by topic and can be found in the subdirectory `exercises/<topic>`.
For every topic, there is an additional `README.md` file with some resources to get you started on the topic.
We highly recommend that you have a look at them before you start 📚️
The task is simple. Most exercises contain an error that keeps them from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute: Most exercises contain an error that keeps them from compiling, and it's up to you to fix it!
Some exercises contain tests that need to pass for the exercise to be done ✅
```bash Search for `TODO` and `todo!()` to find out what you need to change.
rustlings watch Ask for hints by entering `h` in the _watch mode_ 💡
```
This will try to verify the completion of every exercise in a predetermined order (what we think is best for newcomers). It will also rerun automatically every time you change a file in the `exercises/` directory. If you want to only run it once, you can use: ### Watch Mode
```bash After [initialization](#initialization), Rustlings can be launched by simply running the command `rustlings`.
rustlings verify
```
This will do the same as watch, but it'll quit after running. This will start the _watch mode_ which walks you through the exercises in a predefined order (what we think is best for newcomers).
It will rerun the current exercise automatically every time you change the exercise's file in the `exercises/` directory.
In case you want to go by your own order, or want to only verify a single exercise, you can run: <details>
<summary><strong>If detecting file changes in the <code>exercises/</code> directory fails…</strong> (<em>click to expand</em>)</summary>
```bash > You can add the **`--manual-run`** flag (`rustlings --manual-run`) to manually rerun the current exercise by entering `r` in the watch mode.
rustlings run myExercise1 >
``` > Please [report the issue](https://github.com/rust-lang/rustlings/issues/new) with some information about your operating system and whether you run Rustlings in a container or virtual machine (e.g. WSL).
Or simply use the following command to run the next unsolved exercise in the course: </details>
```bash ### Exercise List
rustlings run next
```
In case you get stuck, you can run the following command to get a hint for your In the [watch mode](#watch-mode) (after launching `rustlings`), you can enter `l` to open the interactive exercise list.
exercise:
```bash The list allows you to…
rustlings hint myExercise1
```
You can also get the hint for the next unsolved exercise with the following command: - See the status of all exercises (done or pending)
- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
- `r`: Reset status and file of an exercise (you need to _reload/reopen_ its file in your editor afterwards)
```bash See the footer of the list for all possible keys.
rustlings hint next
```
To check your progress, you can run the following command:
```bash
rustlings list
```
## Testing yourself
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`.
## Enabling `rust-analyzer`
Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise.
## Continuing On ## Continuing On
Once you've completed Rustlings, put your new knowledge to good use! Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to. Once you've completed Rustlings, put your new knowledge to good use!
Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
On [CodeCrafters](https://codecrafters.io/rust) you can get some quality practice through recreating different technologies from scratch in Rust (e.g Build your own BitTorrent, HTTP Server, SQLite, etc). ## Third-Party Exercises
Do you want to create your own set of Rustlings exercises to focus on some specific topic?
Or do you want to translate the original Rustlings exercises?
Then follow the link to the guide about [third-party exercises](THIRD_PARTY_EXERCISES.md)!
## Uninstalling Rustlings ## Uninstalling Rustlings
If you want to remove Rustlings from your system, there are two steps. First, you'll need to remove the exercises folder that the install script created If you want to remove Rustlings from your system, run the following command:
for you:
```bash
rm -rf rustlings # or your custom folder name, if you chose and or renamed it
```
Second, run `cargo uninstall` to remove the `rustlings` binary:
```bash ```bash
cargo uninstall rustlings cargo uninstall rustlings
``` ```
Now you should be done!
## Contributing ## Contributing
See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md). See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md) 🔗
## Contributors ✨ ## Contributors ✨
Thanks goes to the wonderful people listed in [AUTHORS.md](https://github.com/rust-lang/rustlings/blob/main/AUTHORS.md) 🎉 Thanks to [all the wonderful contributors](https://github.com/rust-lang/rustlings/graphs/contributors) 🎉

53
THIRD_PARTY_EXERCISES.md Normal file
View file

@ -0,0 +1,53 @@
# Third-Party Exercises
The support of Rustlings for third-party exercises allows you to create your own set of Rustlings exercises to focus on some specific topic.
You could also offer a translatation of the original Rustlings exercises as third-party exercises.
## Getting started
To create third-party exercises, install Rustlings and run `rustlings dev new PROJECT_NAME`.
This command will, similar to `cargo new PROJECT_NAME`, create a template directory called `PROJECT_NAME` with all what you need to get started.
Read the comments in the generated `info.toml` file to understand its format.
It allows you to set a custom welcome and final message and specify the metadata of every exercise.
## Create an exercise
Here is an example of the metadata of one file:
```toml
[[exercises]]
name = "intro1"
hint = """
To finish this exercise, you need to …
This link might help you …"""
```
After entering this in `info.toml`, create the file `intro1.rs` in the `exercises/` directory.
The exercise needs to contain a `main` function, but it can be empty.
Adding tests is recommended.
Look at the official Rustlings exercises for inspiration.
You can optionally add a solution file `intro1.rs` to the `solutions/` directory.
Now, run `rustlings dev check`.
It will tell you about any issues with your exercises.
For example, it will tell you to run `rustlings dev update` to update the `Cargo.toml` file to include the new exercise `intro1`.
`rustlings dev check` will also run your solutions (if you have any) to make sure that they run successfully.
That's it!
You finished your first exercise 🎉
## Publish
Now, add more exercises and publish them as a Git repository.
Users just have to clone that repository and run `rustlings` in it to start working on your set of exercises just like the official ones.
One difference to the official exercises is that the solution files will not be hidden until the user finishes an exercise.
But you can trust the users to not look at the solution too early 😉
## Share
After publishing your set of exercises, open an issue or a pull request in the official Rustlings repository to link to your project in the README 😃

1
dev-Cargo.toml Symbolic link
View file

@ -0,0 +1 @@
dev/Cargo.toml

197
dev/Cargo.toml Normal file
View file

@ -0,0 +1,197 @@
# Don't edit the `bin` list manually! It is updated by `cargo run -- dev update`. This comment line will be stripped in `rustlings init`.
bin = [
{ name = "intro1", path = "../exercises/00_intro/intro1.rs" },
{ name = "intro1_sol", path = "../solutions/00_intro/intro1.rs" },
{ name = "intro2", path = "../exercises/00_intro/intro2.rs" },
{ name = "intro2_sol", path = "../solutions/00_intro/intro2.rs" },
{ name = "variables1", path = "../exercises/01_variables/variables1.rs" },
{ name = "variables1_sol", path = "../solutions/01_variables/variables1.rs" },
{ name = "variables2", path = "../exercises/01_variables/variables2.rs" },
{ name = "variables2_sol", path = "../solutions/01_variables/variables2.rs" },
{ name = "variables3", path = "../exercises/01_variables/variables3.rs" },
{ name = "variables3_sol", path = "../solutions/01_variables/variables3.rs" },
{ name = "variables4", path = "../exercises/01_variables/variables4.rs" },
{ name = "variables4_sol", path = "../solutions/01_variables/variables4.rs" },
{ name = "variables5", path = "../exercises/01_variables/variables5.rs" },
{ name = "variables5_sol", path = "../solutions/01_variables/variables5.rs" },
{ name = "variables6", path = "../exercises/01_variables/variables6.rs" },
{ name = "variables6_sol", path = "../solutions/01_variables/variables6.rs" },
{ name = "functions1", path = "../exercises/02_functions/functions1.rs" },
{ name = "functions1_sol", path = "../solutions/02_functions/functions1.rs" },
{ name = "functions2", path = "../exercises/02_functions/functions2.rs" },
{ name = "functions2_sol", path = "../solutions/02_functions/functions2.rs" },
{ name = "functions3", path = "../exercises/02_functions/functions3.rs" },
{ name = "functions3_sol", path = "../solutions/02_functions/functions3.rs" },
{ name = "functions4", path = "../exercises/02_functions/functions4.rs" },
{ name = "functions4_sol", path = "../solutions/02_functions/functions4.rs" },
{ name = "functions5", path = "../exercises/02_functions/functions5.rs" },
{ name = "functions5_sol", path = "../solutions/02_functions/functions5.rs" },
{ name = "if1", path = "../exercises/03_if/if1.rs" },
{ name = "if1_sol", path = "../solutions/03_if/if1.rs" },
{ name = "if2", path = "../exercises/03_if/if2.rs" },
{ name = "if2_sol", path = "../solutions/03_if/if2.rs" },
{ name = "if3", path = "../exercises/03_if/if3.rs" },
{ name = "if3_sol", path = "../solutions/03_if/if3.rs" },
{ name = "quiz1", path = "../exercises/quizzes/quiz1.rs" },
{ name = "quiz1_sol", path = "../solutions/quizzes/quiz1.rs" },
{ name = "primitive_types1", path = "../exercises/04_primitive_types/primitive_types1.rs" },
{ name = "primitive_types1_sol", path = "../solutions/04_primitive_types/primitive_types1.rs" },
{ name = "primitive_types2", path = "../exercises/04_primitive_types/primitive_types2.rs" },
{ name = "primitive_types2_sol", path = "../solutions/04_primitive_types/primitive_types2.rs" },
{ name = "primitive_types3", path = "../exercises/04_primitive_types/primitive_types3.rs" },
{ name = "primitive_types3_sol", path = "../solutions/04_primitive_types/primitive_types3.rs" },
{ name = "primitive_types4", path = "../exercises/04_primitive_types/primitive_types4.rs" },
{ name = "primitive_types4_sol", path = "../solutions/04_primitive_types/primitive_types4.rs" },
{ name = "primitive_types5", path = "../exercises/04_primitive_types/primitive_types5.rs" },
{ name = "primitive_types5_sol", path = "../solutions/04_primitive_types/primitive_types5.rs" },
{ name = "primitive_types6", path = "../exercises/04_primitive_types/primitive_types6.rs" },
{ name = "primitive_types6_sol", path = "../solutions/04_primitive_types/primitive_types6.rs" },
{ name = "vecs1", path = "../exercises/05_vecs/vecs1.rs" },
{ name = "vecs1_sol", path = "../solutions/05_vecs/vecs1.rs" },
{ name = "vecs2", path = "../exercises/05_vecs/vecs2.rs" },
{ name = "vecs2_sol", path = "../solutions/05_vecs/vecs2.rs" },
{ name = "move_semantics1", path = "../exercises/06_move_semantics/move_semantics1.rs" },
{ name = "move_semantics1_sol", path = "../solutions/06_move_semantics/move_semantics1.rs" },
{ name = "move_semantics2", path = "../exercises/06_move_semantics/move_semantics2.rs" },
{ name = "move_semantics2_sol", path = "../solutions/06_move_semantics/move_semantics2.rs" },
{ name = "move_semantics3", path = "../exercises/06_move_semantics/move_semantics3.rs" },
{ name = "move_semantics3_sol", path = "../solutions/06_move_semantics/move_semantics3.rs" },
{ name = "move_semantics4", path = "../exercises/06_move_semantics/move_semantics4.rs" },
{ name = "move_semantics4_sol", path = "../solutions/06_move_semantics/move_semantics4.rs" },
{ name = "move_semantics5", path = "../exercises/06_move_semantics/move_semantics5.rs" },
{ name = "move_semantics5_sol", path = "../solutions/06_move_semantics/move_semantics5.rs" },
{ name = "structs1", path = "../exercises/07_structs/structs1.rs" },
{ name = "structs1_sol", path = "../solutions/07_structs/structs1.rs" },
{ name = "structs2", path = "../exercises/07_structs/structs2.rs" },
{ name = "structs2_sol", path = "../solutions/07_structs/structs2.rs" },
{ name = "structs3", path = "../exercises/07_structs/structs3.rs" },
{ name = "structs3_sol", path = "../solutions/07_structs/structs3.rs" },
{ name = "enums1", path = "../exercises/08_enums/enums1.rs" },
{ name = "enums1_sol", path = "../solutions/08_enums/enums1.rs" },
{ name = "enums2", path = "../exercises/08_enums/enums2.rs" },
{ name = "enums2_sol", path = "../solutions/08_enums/enums2.rs" },
{ name = "enums3", path = "../exercises/08_enums/enums3.rs" },
{ name = "enums3_sol", path = "../solutions/08_enums/enums3.rs" },
{ name = "strings1", path = "../exercises/09_strings/strings1.rs" },
{ name = "strings1_sol", path = "../solutions/09_strings/strings1.rs" },
{ name = "strings2", path = "../exercises/09_strings/strings2.rs" },
{ name = "strings2_sol", path = "../solutions/09_strings/strings2.rs" },
{ name = "strings3", path = "../exercises/09_strings/strings3.rs" },
{ name = "strings3_sol", path = "../solutions/09_strings/strings3.rs" },
{ name = "strings4", path = "../exercises/09_strings/strings4.rs" },
{ name = "strings4_sol", path = "../solutions/09_strings/strings4.rs" },
{ name = "modules1", path = "../exercises/10_modules/modules1.rs" },
{ name = "modules1_sol", path = "../solutions/10_modules/modules1.rs" },
{ name = "modules2", path = "../exercises/10_modules/modules2.rs" },
{ name = "modules2_sol", path = "../solutions/10_modules/modules2.rs" },
{ name = "modules3", path = "../exercises/10_modules/modules3.rs" },
{ name = "modules3_sol", path = "../solutions/10_modules/modules3.rs" },
{ name = "hashmaps1", path = "../exercises/11_hashmaps/hashmaps1.rs" },
{ name = "hashmaps1_sol", path = "../solutions/11_hashmaps/hashmaps1.rs" },
{ name = "hashmaps2", path = "../exercises/11_hashmaps/hashmaps2.rs" },
{ name = "hashmaps2_sol", path = "../solutions/11_hashmaps/hashmaps2.rs" },
{ name = "hashmaps3", path = "../exercises/11_hashmaps/hashmaps3.rs" },
{ name = "hashmaps3_sol", path = "../solutions/11_hashmaps/hashmaps3.rs" },
{ name = "quiz2", path = "../exercises/quizzes/quiz2.rs" },
{ name = "quiz2_sol", path = "../solutions/quizzes/quiz2.rs" },
{ name = "options1", path = "../exercises/12_options/options1.rs" },
{ name = "options1_sol", path = "../solutions/12_options/options1.rs" },
{ name = "options2", path = "../exercises/12_options/options2.rs" },
{ name = "options2_sol", path = "../solutions/12_options/options2.rs" },
{ name = "options3", path = "../exercises/12_options/options3.rs" },
{ name = "options3_sol", path = "../solutions/12_options/options3.rs" },
{ name = "errors1", path = "../exercises/13_error_handling/errors1.rs" },
{ name = "errors1_sol", path = "../solutions/13_error_handling/errors1.rs" },
{ name = "errors2", path = "../exercises/13_error_handling/errors2.rs" },
{ name = "errors2_sol", path = "../solutions/13_error_handling/errors2.rs" },
{ name = "errors3", path = "../exercises/13_error_handling/errors3.rs" },
{ name = "errors3_sol", path = "../solutions/13_error_handling/errors3.rs" },
{ name = "errors4", path = "../exercises/13_error_handling/errors4.rs" },
{ name = "errors4_sol", path = "../solutions/13_error_handling/errors4.rs" },
{ name = "errors5", path = "../exercises/13_error_handling/errors5.rs" },
{ name = "errors5_sol", path = "../solutions/13_error_handling/errors5.rs" },
{ name = "errors6", path = "../exercises/13_error_handling/errors6.rs" },
{ name = "errors6_sol", path = "../solutions/13_error_handling/errors6.rs" },
{ name = "generics1", path = "../exercises/14_generics/generics1.rs" },
{ name = "generics1_sol", path = "../solutions/14_generics/generics1.rs" },
{ name = "generics2", path = "../exercises/14_generics/generics2.rs" },
{ name = "generics2_sol", path = "../solutions/14_generics/generics2.rs" },
{ name = "traits1", path = "../exercises/15_traits/traits1.rs" },
{ name = "traits1_sol", path = "../solutions/15_traits/traits1.rs" },
{ name = "traits2", path = "../exercises/15_traits/traits2.rs" },
{ name = "traits2_sol", path = "../solutions/15_traits/traits2.rs" },
{ name = "traits3", path = "../exercises/15_traits/traits3.rs" },
{ name = "traits3_sol", path = "../solutions/15_traits/traits3.rs" },
{ name = "traits4", path = "../exercises/15_traits/traits4.rs" },
{ name = "traits4_sol", path = "../solutions/15_traits/traits4.rs" },
{ name = "traits5", path = "../exercises/15_traits/traits5.rs" },
{ name = "traits5_sol", path = "../solutions/15_traits/traits5.rs" },
{ name = "quiz3", path = "../exercises/quizzes/quiz3.rs" },
{ name = "quiz3_sol", path = "../solutions/quizzes/quiz3.rs" },
{ name = "lifetimes1", path = "../exercises/16_lifetimes/lifetimes1.rs" },
{ name = "lifetimes1_sol", path = "../solutions/16_lifetimes/lifetimes1.rs" },
{ name = "lifetimes2", path = "../exercises/16_lifetimes/lifetimes2.rs" },
{ name = "lifetimes2_sol", path = "../solutions/16_lifetimes/lifetimes2.rs" },
{ name = "lifetimes3", path = "../exercises/16_lifetimes/lifetimes3.rs" },
{ name = "lifetimes3_sol", path = "../solutions/16_lifetimes/lifetimes3.rs" },
{ name = "tests1", path = "../exercises/17_tests/tests1.rs" },
{ name = "tests1_sol", path = "../solutions/17_tests/tests1.rs" },
{ name = "tests2", path = "../exercises/17_tests/tests2.rs" },
{ name = "tests2_sol", path = "../solutions/17_tests/tests2.rs" },
{ name = "tests3", path = "../exercises/17_tests/tests3.rs" },
{ name = "tests3_sol", path = "../solutions/17_tests/tests3.rs" },
{ name = "iterators1", path = "../exercises/18_iterators/iterators1.rs" },
{ name = "iterators1_sol", path = "../solutions/18_iterators/iterators1.rs" },
{ name = "iterators2", path = "../exercises/18_iterators/iterators2.rs" },
{ name = "iterators2_sol", path = "../solutions/18_iterators/iterators2.rs" },
{ name = "iterators3", path = "../exercises/18_iterators/iterators3.rs" },
{ name = "iterators3_sol", path = "../solutions/18_iterators/iterators3.rs" },
{ name = "iterators4", path = "../exercises/18_iterators/iterators4.rs" },
{ name = "iterators4_sol", path = "../solutions/18_iterators/iterators4.rs" },
{ name = "iterators5", path = "../exercises/18_iterators/iterators5.rs" },
{ name = "iterators5_sol", path = "../solutions/18_iterators/iterators5.rs" },
{ name = "box1", path = "../exercises/19_smart_pointers/box1.rs" },
{ name = "box1_sol", path = "../solutions/19_smart_pointers/box1.rs" },
{ name = "rc1", path = "../exercises/19_smart_pointers/rc1.rs" },
{ name = "rc1_sol", path = "../solutions/19_smart_pointers/rc1.rs" },
{ name = "arc1", path = "../exercises/19_smart_pointers/arc1.rs" },
{ name = "arc1_sol", path = "../solutions/19_smart_pointers/arc1.rs" },
{ name = "cow1", path = "../exercises/19_smart_pointers/cow1.rs" },
{ name = "cow1_sol", path = "../solutions/19_smart_pointers/cow1.rs" },
{ name = "threads1", path = "../exercises/20_threads/threads1.rs" },
{ name = "threads1_sol", path = "../solutions/20_threads/threads1.rs" },
{ name = "threads2", path = "../exercises/20_threads/threads2.rs" },
{ name = "threads2_sol", path = "../solutions/20_threads/threads2.rs" },
{ name = "threads3", path = "../exercises/20_threads/threads3.rs" },
{ name = "threads3_sol", path = "../solutions/20_threads/threads3.rs" },
{ name = "macros1", path = "../exercises/21_macros/macros1.rs" },
{ name = "macros1_sol", path = "../solutions/21_macros/macros1.rs" },
{ name = "macros2", path = "../exercises/21_macros/macros2.rs" },
{ name = "macros2_sol", path = "../solutions/21_macros/macros2.rs" },
{ name = "macros3", path = "../exercises/21_macros/macros3.rs" },
{ name = "macros3_sol", path = "../solutions/21_macros/macros3.rs" },
{ name = "macros4", path = "../exercises/21_macros/macros4.rs" },
{ name = "macros4_sol", path = "../solutions/21_macros/macros4.rs" },
{ name = "clippy1", path = "../exercises/22_clippy/clippy1.rs" },
{ name = "clippy1_sol", path = "../solutions/22_clippy/clippy1.rs" },
{ name = "clippy2", path = "../exercises/22_clippy/clippy2.rs" },
{ name = "clippy2_sol", path = "../solutions/22_clippy/clippy2.rs" },
{ name = "clippy3", path = "../exercises/22_clippy/clippy3.rs" },
{ name = "clippy3_sol", path = "../solutions/22_clippy/clippy3.rs" },
{ name = "using_as", path = "../exercises/23_conversions/using_as.rs" },
{ name = "using_as_sol", path = "../solutions/23_conversions/using_as.rs" },
{ name = "from_into", path = "../exercises/23_conversions/from_into.rs" },
{ name = "from_into_sol", path = "../solutions/23_conversions/from_into.rs" },
{ name = "from_str", path = "../exercises/23_conversions/from_str.rs" },
{ name = "from_str_sol", path = "../solutions/23_conversions/from_str.rs" },
{ name = "try_from_into", path = "../exercises/23_conversions/try_from_into.rs" },
{ name = "try_from_into_sol", path = "../solutions/23_conversions/try_from_into.rs" },
{ name = "as_ref_mut", path = "../exercises/23_conversions/as_ref_mut.rs" },
{ name = "as_ref_mut_sol", path = "../solutions/23_conversions/as_ref_mut.rs" },
]
[package]
name = "exercises"
edition = "2021"
# Don't publish the exercises on crates.io!
publish = false

1
dev/rustlings-repo.txt Normal file
View file

@ -0,0 +1 @@
This file is used to check if the user tries to run Rustlings in the repository (the method before v6)

View file

@ -1,19 +1,9 @@
// intro1.rs // TODO: We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and feel
// ready for the next exercise, enter `n` in the terminal.
// //
// About this `I AM NOT DONE` thing: // The exercise file will be reloaded when you change one of the lines below!
// We sometimes encourage you to keep trying things on a given exercise, even // Try adding a new `println!` and check the updated output in the terminal.
// after you already figured it out. If you got everything working and feel
// ready for the next exercise, remove the `I AM NOT DONE` comment below.
//
// If you're running this using `rustlings watch`: The exercise file will be
// reloaded when you change one of the lines below! Try adding a `println!`
// line, or try changing what it outputs in your terminal. Try removing a
// semicolon and see what happens!
//
// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
println!("Hello and"); println!("Hello and");
@ -29,13 +19,7 @@ fn main() {
println!("or logic error. The central concept behind Rustlings is to fix these errors and"); println!("or logic error. The central concept behind Rustlings is to fix these errors and");
println!("solve the exercises. Good luck!"); println!("solve the exercises. Good luck!");
println!(); println!();
println!("The source for this exercise is in `exercises/00_intro/intro1.rs`. Have a look!"); println!("The file of this exercise is `exercises/00_intro/intro1.rs`. Have a look!");
println!( println!("The current exercise path will be always shown under the progress bar.");
"Going forward, the source of the exercises will always be in the success/failure output." println!("You can click on the path to open the exercise file in your editor.");
);
println!();
println!(
"If you want to use rust-analyzer, Rust's LSP implementation, make sure your editor is set"
);
println!("up, and then run `rustlings lsp` before continuing.")
} }

View file

@ -1,12 +1,4 @@
// intro2.rs
//
// Make the code print a greeting to the world.
//
// Execute `rustlings hint intro2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
printline!("Hello there!") // TODO: Fix the code to print "Hello world!".
printline!("Hello world!");
} }

View file

@ -1,13 +1,6 @@
// variables1.rs
//
// Make me compile!
//
// Execute `rustlings hint variables1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
// TODO: Add missing keyword.
x = 5; x = 5;
println!("x has the value {}", x);
println!("x has the value {x}");
} }

View file

@ -1,12 +1,7 @@
// variables2.rs
//
// Execute `rustlings hint variables2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
// TODO: Change the line below to fix the compiler error.
let x; let x;
if x == 10 { if x == 10 {
println!("x is ten!"); println!("x is ten!");
} else { } else {

View file

@ -1,11 +1,6 @@
// variables3.rs
//
// Execute `rustlings hint variables3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
// TODO: Change the line below to fix the compiler error.
let x: i32; let x: i32;
println!("Number {}", x);
println!("Number {x}");
} }

View file

@ -1,13 +1,8 @@
// variables4.rs // TODO: Fix the compiler error.
//
// Execute `rustlings hint variables4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
let x = 3; let x = 3;
println!("Number {}", x); println!("Number {x}");
x = 5; // don't change this line
println!("Number {}", x); x = 5; // Don't change this line
println!("Number {x}");
} }

View file

@ -1,13 +1,8 @@
// variables5.rs
//
// Execute `rustlings hint variables5` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
let number = "T-H-R-E-E"; // don't change this line let number = "T-H-R-E-E"; // Don't change this line
println!("Spell a Number : {}", number); println!("Spell a number: {}", number);
number = 3; // don't rename this variable
println!("Number plus two is : {}", number + 2); // TODO: Fix the compiler error by changing the line below without renaming the variable.
number = 3;
println!("Number plus two is: {}", number + 2);
} }

View file

@ -1,11 +1,6 @@
// variables6.rs // TODO: Change the line below to fix the compiler error.
//
// Execute `rustlings hint variables6` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
const NUMBER = 3; const NUMBER = 3;
fn main() { fn main() {
println!("Number {}", NUMBER); println!("Number: {NUMBER}");
} }

View file

@ -1,10 +1,5 @@
// functions1.rs // TODO: Add some function with the name `call_me` without arguments or a return value.
//
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
call_me(); call_me(); // Don't change this line
} }

View file

@ -1,16 +1,10 @@
// functions2.rs // TODO: Add the missing type of the argument `num` after the colon `:`.
//
// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() {
call_me(3);
}
fn call_me(num:) { fn call_me(num:) {
for i in 0..num { for i in 0..num {
println!("Ring! Call number {}", i + 1); println!("Ring! Call number {}", i + 1);
} }
} }
fn main() {
call_me(3);
}

View file

@ -1,16 +1,10 @@
// functions3.rs
//
// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() {
call_me();
}
fn call_me(num: u32) { fn call_me(num: u32) {
for i in 0..num { for i in 0..num {
println!("Ring! Call number {}", i + 1); println!("Ring! Call number {}", i + 1);
} }
} }
fn main() {
// TODO: Fix the function call.
call_me();
}

View file

@ -1,21 +1,14 @@
// functions4.rs
//
// This store is having a sale where if the price is an even number, you get 10 // This store is having a sale where if the price is an even number, you get 10
// Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. (Don't worry // Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
// about the function bodies themselves, we're only interested in the signatures // Don't worry about the function bodies themselves, we are only interested in
// for now. If anything, this is a good way to peek ahead to future exercises!) // the signatures for now.
//
// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE fn is_even(num: i64) -> bool {
num % 2 == 0
fn main() {
let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
} }
fn sale_price(price: i32) -> { // TODO: Fix the function signature.
fn sale_price(price: i64) -> {
if is_even(price) { if is_even(price) {
price - 10 price - 10
} else { } else {
@ -23,6 +16,7 @@ fn sale_price(price: i32) -> {
} }
} }
fn is_even(num: i32) -> bool { fn main() {
num % 2 == 0 let original_price = 51;
println!("Your sale price is {}", sale_price(original_price));
} }

View file

@ -1,15 +1,9 @@
// functions5.rs // TODO: Fix the function body without changing the signature.
//
// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() {
let answer = square(3);
println!("The square of 3 is {}", answer);
}
fn square(num: i32) -> i32 { fn square(num: i32) -> i32 {
num * num; num * num;
} }
fn main() {
let answer = square(3);
println!("The square of 3 is {answer}");
}

View file

@ -1,16 +1,15 @@
// if1.rs fn bigger(a: i32, b: i32) -> i32 {
// // TODO: Complete this function to return the bigger number!
// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint. // If both numbers are equal, any of them can be returned.
// I AM NOT DONE
pub fn bigger(a: i32, b: i32) -> i32 {
// Complete this function to return the bigger number!
// Do not use: // Do not use:
// - another function call // - another function call
// - additional variables // - additional variables
} }
fn main() {
// You can optionally experiment here.
}
// Don't mind this for now :) // Don't mind this for now :)
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -1,13 +1,5 @@
// if2.rs // TODO: Fix the compiler error on this function.
// fn foo_if_fizz(fizzish: &str) -> &str {
// Step 1: Make me compile!
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
//
// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" { if fizzish == "fizz" {
"foo" "foo"
} else { } else {
@ -15,23 +7,29 @@ pub fn foo_if_fizz(fizzish: &str) -> &str {
} }
} }
// No test changes needed! fn main() {
// You can optionally experiment here.
}
// TODO: Read the tests to understand the desired behavior.
// Make all tests pass without changing them.
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn foo_for_fizz() { fn foo_for_fizz() {
assert_eq!(foo_if_fizz("fizz"), "foo") // This means that calling `foo_if_fizz` with the argument "fizz" should return "foo".
assert_eq!(foo_if_fizz("fizz"), "foo");
} }
#[test] #[test]
fn bar_for_fuzz() { fn bar_for_fuzz() {
assert_eq!(foo_if_fizz("fuzz"), "bar") assert_eq!(foo_if_fizz("fuzz"), "bar");
} }
#[test] #[test]
fn default_to_baz() { fn default_to_baz() {
assert_eq!(foo_if_fizz("literally anything"), "baz") assert_eq!(foo_if_fizz("literally anything"), "baz");
} }
} }

View file

@ -1,10 +1,5 @@
// if3.rs fn animal_habitat(animal: &str) -> &str {
// // TODO: Fix the compiler error in the statement below.
// Execute `rustlings hint if3` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub fn animal_habitat(animal: &str) -> &'static str {
let identifier = if animal == "crab" { let identifier = if animal == "crab" {
1 1
} else if animal == "gopher" { } else if animal == "gopher" {
@ -15,8 +10,8 @@ pub fn animal_habitat(animal: &str) -> &'static str {
"Unknown" "Unknown"
}; };
// DO NOT CHANGE THIS STATEMENT BELOW // Don't change the expression below!
let habitat = if identifier == 1 { if identifier == 1 {
"Beach" "Beach"
} else if identifier == 2 { } else if identifier == 2 {
"Burrow" "Burrow"
@ -24,12 +19,14 @@ pub fn animal_habitat(animal: &str) -> &'static str {
"Desert" "Desert"
} else { } else {
"Unknown" "Unknown"
}; }
habitat
} }
// No test changes needed. fn main() {
// You can optionally experiment here.
}
// Don't change the tests!
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -1,19 +1,14 @@
// primitive_types1.rs // Booleans (`bool`)
//
// Fill in the rest of the line that has code missing! No hints, there's no
// tricks, just get used to typing these :)
// I AM NOT DONE
fn main() { fn main() {
// Booleans (`bool`)
let is_morning = true; let is_morning = true;
if is_morning { if is_morning {
println!("Good morning!"); println!("Good morning!");
} }
let // Finish the rest of this line like the example! Or make it be false! // TODO: Define a boolean variable with the name `is_evening` before the `if` statement below.
// The value of the variable should be the negation (opposite) of `is_morning`.
// let …
if is_evening { if is_evening {
println!("Good evening!"); println!("Good evening!");
} }

View file

@ -1,13 +1,6 @@
// primitive_types2.rs // Characters (`char`)
//
// Fill in the rest of the line that has code missing! No hints, there's no
// tricks, just get used to typing these :)
// I AM NOT DONE
fn main() { fn main() {
// Characters (`char`)
// Note the _single_ quotes, these are different from the double quotes // Note the _single_ quotes, these are different from the double quotes
// you've been seeing around. // you've been seeing around.
let my_first_initial = 'C'; let my_first_initial = 'C';
@ -19,9 +12,12 @@ fn main() {
println!("Neither alphabetic nor numeric!"); println!("Neither alphabetic nor numeric!");
} }
let // Finish this line like the example! What's your favorite character? // TODO: Analogous to the example before, declare a variable called `your_character`
// Try a letter, try a number, try a special character, try a character // below with your favorite character.
// from a different language than your own, try an emoji! // Try a letter, try a digit (in single quotes), try a special character, try a character
// from a different language than your own, try an emoji 😉
// let your_character = '';
if your_character.is_alphabetic() { if your_character.is_alphabetic() {
println!("Alphabetical!"); println!("Alphabetical!");
} else if your_character.is_numeric() { } else if your_character.is_numeric() {

View file

@ -1,19 +1,11 @@
// primitive_types3.rs
//
// Create an array with at least 100 elements in it where the ??? is.
//
// Execute `rustlings hint primitive_types3` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
fn main() { fn main() {
let a = ??? // TODO: Create an array called `a` with at least 100 elements in it.
// let a = ???
if a.len() >= 100 { if a.len() >= 100 {
println!("Wow, that's a big array!"); println!("Wow, that's a big array!");
} else { } else {
println!("Meh, I eat arrays like that for breakfast."); println!("Meh, I eat arrays like that for breakfast.");
panic!("Array not big enough, more elements needed") panic!("Array not big enough, more elements needed");
} }
} }

View file

@ -1,17 +1,16 @@
// primitive_types4.rs fn main() {
// // You can optionally experiment here.
// Get a slice out of Array a where the ??? is so that the test passes. }
//
// Execute `rustlings hint primitive_types4` or use the `hint` watch subcommand #[cfg(test)]
// for a hint. mod tests {
#[test]
// I AM NOT DONE fn slice_out_of_array() {
let a = [1, 2, 3, 4, 5];
#[test]
fn slice_out_of_array() { // TODO: Get a slice called `nice_slice` out of the array `a` so that the test passes.
let a = [1, 2, 3, 4, 5]; // let nice_slice = ???
let nice_slice = ??? assert_eq!([2, 3, 4], nice_slice);
}
assert_eq!([2, 3, 4], nice_slice)
} }

View file

@ -1,15 +1,8 @@
// primitive_types5.rs
//
// Destructure the `cat` tuple so that the println will work.
//
// Execute `rustlings hint primitive_types5` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
fn main() { fn main() {
let cat = ("Furry McFurson", 3.5); let cat = ("Furry McFurson", 3.5);
let /* your pattern here */ = cat;
println!("{} is {} years old.", name, age); // TODO: Destructure the `cat` tuple in one statement so that the println works.
// let /* your pattern here */ = cat;
println!("{name} is {age} years old");
} }

View file

@ -1,19 +1,17 @@
// primitive_types6.rs fn main() {
// // You can optionally experiment here.
// Use a tuple index to access the second element of `numbers`. You can put the }
// expression for the second element where ??? is so that the test passes.
// #[cfg(test)]
// Execute `rustlings hint primitive_types6` or use the `hint` watch subcommand mod tests {
// for a hint. #[test]
fn indexing_tuple() {
// I AM NOT DONE let numbers = (1, 2, 3);
#[test] // TODO: Use a tuple index to access the second element of `numbers`
fn indexing_tuple() { // and assign it to a variable called `second`.
let numbers = (1, 2, 3); // let second = ???;
// Replace below ??? with the tuple indexing syntax.
let second = ???; assert_eq!(second, 2, "This is not the 2nd number in the tuple!");
}
assert_eq!(2, second,
"This is not the 2nd number in the tuple!")
} }

View file

@ -1,21 +1,17 @@
// vecs1.rs
//
// Your task is to create a `Vec` which holds the exact same elements as in the
// array `a`.
//
// Make me compile and pass the test!
//
// Execute `rustlings hint vecs1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn array_and_vec() -> ([i32; 4], Vec<i32>) { fn array_and_vec() -> ([i32; 4], Vec<i32>) {
let a = [10, 20, 30, 40]; // a plain array let a = [10, 20, 30, 40]; // Array
let v = // TODO: declare your vector here with the macro for vectors
// TODO: Create a vector called `v` which contains the exact same elements as in the array `a`.
// Use the vector macro.
// let v = ???;
(a, v) (a, v)
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -23,6 +19,6 @@ mod tests {
#[test] #[test]
fn test_array_and_vec_similarity() { fn test_array_and_vec_similarity() {
let (a, v) = array_and_vec(); let (a, v) = array_and_vec();
assert_eq!(a, v[..]); assert_eq!(a, *v);
} }
} }

View file

@ -1,31 +1,36 @@
// vecs2.rs fn vec_loop(input: &[i32]) -> Vec<i32> {
// let mut output = Vec::new();
// A Vec of even numbers is given. Your task is to complete the loop so that
// each number in the Vec is multiplied by 2.
//
// Make me pass the test!
//
// Execute `rustlings hint vecs2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE for element in input {
// TODO: Multiply each element in the `input` slice by 2 and push it to
fn vec_loop(mut v: Vec<i32>) -> Vec<i32> { // the `output` vector.
for element in v.iter_mut() {
// TODO: Fill this up so that each element in the Vec `v` is
// multiplied by 2.
???
} }
// At this point, `v` should be equal to [4, 8, 12, 16, 20]. output
v
} }
fn vec_map(v: &Vec<i32>) -> Vec<i32> { fn vec_map_example(input: &[i32]) -> Vec<i32> {
v.iter().map(|element| { // An example of collecting a vector after mapping.
// TODO: Do the same thing as above - but instead of mutating the // We map each element of the `input` slice to its value plus 1.
// Vec, you can just return the new number! // If the input is `[1, 2, 3]`, the output is `[2, 3, 4]`.
??? input.iter().map(|element| element + 1).collect()
}).collect() }
fn vec_map(input: &[i32]) -> Vec<i32> {
// TODO: Here, we also want to multiply each element in the `input` slice
// by 2, but with iterator mapping instead of manually pushing into an empty
// vector.
// See the example in the function `vec_map_example` above.
input
.iter()
.map(|element| {
// ???
})
.collect()
}
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -34,17 +39,22 @@ mod tests {
#[test] #[test]
fn test_vec_loop() { fn test_vec_loop() {
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect(); let input = [2, 4, 6, 8, 10];
let ans = vec_loop(v.clone()); let ans = vec_loop(&input);
assert_eq!(ans, [4, 8, 12, 16, 20]);
}
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>()); #[test]
fn test_vec_map_example() {
let input = [1, 2, 3];
let ans = vec_map_example(&input);
assert_eq!(ans, [2, 3, 4]);
} }
#[test] #[test]
fn test_vec_map() { fn test_vec_map() {
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect(); let input = [2, 4, 6, 8, 10];
let ans = vec_map(&v); let ans = vec_map(&input);
assert_eq!(ans, [4, 8, 12, 16, 20]);
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>());
} }
} }

View file

@ -1,19 +1,4 @@
// move_semantics1.rs // TODO: Fix the compiler error in this function.
//
// Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
#[test]
fn main() {
let vec0 = vec![22, 44, 66];
let vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let vec = vec; let vec = vec;
@ -21,3 +6,19 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec vec
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn move_semantics1() {
let vec0 = vec![22, 44, 66];
let vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]);
}
}

View file

@ -1,22 +1,3 @@
// move_semantics2.rs
//
// Make the test pass by finding a way to keep both Vecs separate!
//
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
#[test]
fn main() {
let vec0 = vec![22, 44, 66];
let mut vec1 = fill_vec(vec0);
assert_eq!(vec0, vec![22, 44, 66]);
assert_eq!(vec1, vec![22, 44, 66, 88]);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec; let mut vec = vec;
@ -24,3 +5,24 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec vec
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
// TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
// fix the compiler error in the test.
#[test]
fn move_semantics2() {
let vec0 = vec![22, 44, 66];
let vec1 = fill_vec(vec0);
assert_eq!(vec0, [22, 44, 66]);
assert_eq!(vec1, [22, 44, 66, 88]);
}
}

View file

@ -1,24 +1,22 @@
// move_semantics3.rs // TODO: Fix the compiler error in the function without adding any new line.
//
// Make me compile without adding new lines -- just changing existing lines! (no
// lines with multiple semicolons necessary!)
//
// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
#[test]
fn main() {
let vec0 = vec![22, 44, 66];
let mut vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> { fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
vec.push(88); vec.push(88);
vec vec
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn move_semantics3() {
let vec0 = vec![22, 44, 66];
let vec1 = fill_vec(vec0);
assert_eq!(vec1, [22, 44, 66, 88]);
}
}

View file

@ -1,29 +1,18 @@
// move_semantics4.rs
//
// Refactor this code so that instead of passing `vec0` into the `fill_vec`
// function, the Vector gets created in the function itself and passed back to
// the main function.
//
// Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
#[test]
fn main() { fn main() {
let vec0 = vec![22, 44, 66]; // You can optionally experiment here.
let mut vec1 = fill_vec(vec0);
assert_eq!(vec1, vec![22, 44, 66, 88]);
} }
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument - don't change this! #[cfg(test)]
fn fill_vec() -> Vec<i32> { mod tests {
// Instead, let's create and fill the Vec in here - how do you do that? // TODO: Fix the compiler errors only by reordering the lines in the test.
let mut vec = vec; // Don't add, change or remove any line.
#[test]
vec.push(88); fn move_semantics4() {
let mut x = 100;
vec let y = &mut x;
let z = &mut x;
*y += 100;
*z += 1000;
assert_eq!(x, 1200);
}
} }

View file

@ -1,19 +1,24 @@
// move_semantics5.rs #![allow(clippy::ptr_arg)]
//
// Make me compile only by reordering the lines in `main()`, but without adding,
// changing or removing any of them.
//
// Execute `rustlings hint move_semantics5` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE // TODO: Fix the compiler errors without changing anything except adding or
// removing references (the character `&`).
#[test]
fn main() { fn main() {
let mut x = 100; let data = "Rust is great!".to_string();
let y = &mut x;
let z = &mut x; get_char(data);
*y += 100;
*z += 1000; string_uppercase(&data);
assert_eq!(x, 1200); }
// Shouldn't take ownership
fn get_char(data: String) -> char {
data.chars().last().unwrap()
}
// Should take ownership
fn string_uppercase(mut data: &String) {
data = data.to_uppercase();
println!("{data}");
} }

View file

@ -1,28 +0,0 @@
// move_semantics6.rs
//
// You can't change anything except adding or removing references.
//
// Execute `rustlings hint move_semantics6` or use the `hint` watch subcommand
// for a hint.
// I AM NOT DONE
fn main() {
let data = "Rust is great!".to_string();
get_char(data);
string_uppercase(&data);
}
// Should not take ownership
fn get_char(data: String) -> char {
data.chars().last().unwrap()
}
// Should take ownership
fn string_uppercase(mut data: &String) {
data = &data.to_uppercase();
println!("{}", data);
}

View file

@ -1,28 +1,24 @@
// structs1.rs struct ColorRegularStruct {
// // TODO: Add the fields that the test `regular_structs` expects.
// Address all the TODOs to make the tests pass! // What types should the fields have? What are the minimum and maximum values for RGB colors?
//
// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
struct ColorClassicStruct {
// TODO: Something goes here
} }
struct ColorTupleStruct(/* TODO: Something goes here */); struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */);
#[derive(Debug)] #[derive(Debug)]
struct UnitLikeStruct; struct UnitStruct;
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn classic_c_structs() { fn regular_structs() {
// TODO: Instantiate a classic c struct! // TODO: Instantiate a regular struct.
// let green = // let green =
assert_eq!(green.red, 0); assert_eq!(green.red, 0);
@ -32,7 +28,7 @@ mod tests {
#[test] #[test]
fn tuple_structs() { fn tuple_structs() {
// TODO: Instantiate a tuple struct! // TODO: Instantiate a tuple struct.
// let green = // let green =
assert_eq!(green.0, 0); assert_eq!(green.0, 0);
@ -42,10 +38,10 @@ mod tests {
#[test] #[test]
fn unit_structs() { fn unit_structs() {
// TODO: Instantiate a unit-like struct! // TODO: Instantiate a unit struct.
// let unit_like_struct = // let unit_struct =
let message = format!("{:?}s are fun!", unit_like_struct); let message = format!("{unit_struct:?}s are fun!");
assert_eq!(message, "UnitLikeStructs are fun!"); assert_eq!(message, "UnitStructs are fun!");
} }
} }

View file

@ -1,12 +1,3 @@
// structs2.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(Debug)] #[derive(Debug)]
struct Order { struct Order {
name: String, name: String,
@ -30,6 +21,10 @@ fn create_order_template() -> Order {
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -37,8 +32,10 @@ mod tests {
#[test] #[test]
fn your_order() { fn your_order() {
let order_template = create_order_template(); let order_template = create_order_template();
// TODO: Create your own order using the update syntax and template above! // TODO: Create your own order using the update syntax and template above!
// let your_order = // let your_order =
assert_eq!(your_order.name, "Hacker in Rust"); assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year); assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone); assert_eq!(your_order.made_by_phone, order_template.made_by_phone);

View file

@ -1,13 +1,5 @@
// structs3.rs
//
// Structs contain data, but can also have logic. In this exercise we have // Structs contain data, but can also have logic. In this exercise we have
// defined the Package struct and we want to test some logic attached to it. // defined the `Package` struct and we want to test some logic attached to it.
// Make the code compile and the tests pass!
//
// Execute `rustlings hint structs3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(Debug)] #[derive(Debug)]
struct Package { struct Package {
@ -17,29 +9,36 @@ struct Package {
} }
impl Package { impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package { fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
if weight_in_grams < 10 { if weight_in_grams < 10 {
// This is not how you should handle errors in Rust, // This isn't how you should handle errors in Rust, but we will
// but we will learn about error handling later. // learn about error handling later.
panic!("Can not ship a package with weight below 10 grams.") panic!("Can't ship a package with weight below 10 grams");
} else { }
Package {
sender_country, Self {
recipient_country, sender_country,
weight_in_grams, recipient_country,
} weight_in_grams,
} }
} }
fn is_international(&self) -> ??? { // TODO: Add the correct return type to the function signature.
// Something goes here... fn is_international(&self) {
// TODO: Read the tests that use this method to find out when a package
// is considered international.
} }
fn get_fees(&self, cents_per_gram: u32) -> ??? { // TODO: Add the correct return type to the function signature.
// Something goes here... fn get_fees(&self, cents_per_gram: u32) {
// TODO: Calculate the package's fees.
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -1,12 +1,6 @@
// enums1.rs
//
// No hints this time! ;)
// I AM NOT DONE
#[derive(Debug)] #[derive(Debug)]
enum Message { enum Message {
// TODO: define a few types of messages as used below // TODO: Define a few types of messages as used below.
} }
fn main() { fn main() {

View file

@ -1,13 +1,7 @@
// enums2.rs #[allow(dead_code)]
//
// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(Debug)] #[derive(Debug)]
enum Message { enum Message {
// TODO: define the different variants used below // TODO: Define the different variants used below.
} }
#[derive(Debug)] #[derive(Debug)]
@ -18,7 +12,7 @@ struct Point {
impl Message { impl Message {
fn call(&self) { fn call(&self) {
println!("{:?}", self); println!("{self:?}");
} }
} }

View file

@ -1,14 +1,5 @@
// enums3.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint enums3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
enum Message { enum Message {
// TODO: implement the message variant types based on their usage below // TODO: Implement the message variant types based on their usage below.
} }
struct Point { struct Point {
@ -35,25 +26,29 @@ impl State {
} }
fn echo(&mut self, s: String) { fn echo(&mut self, s: String) {
self.message = s self.message = s;
} }
fn resize(&mut self, w: u8, h: u8) { fn resize(&mut self, width: u8, height: u8) {
self.width = w; self.width = width;
self.height = h; self.height = height;
} }
fn move_position(&mut self, p: Point) { fn move_position(&mut self, point: Point) {
self.position = p; self.position = point;
} }
fn process(&mut self, message: Message) { fn process(&mut self, message: Message) {
// TODO: create a match expression to process the different message variants // TODO: Create a match expression to process the different message variants.
// Remember: When passing a tuple as a function argument, you'll need extra parentheses: // Remember: When passing a tuple as a function argument, you'll need extra parentheses:
// fn function((t, u, p, l, e)) // e.g. `foo((t, u, p, l, e))`
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -66,8 +61,9 @@ mod tests {
height: 0, height: 0,
position: Point { x: 0, y: 0 }, position: Point { x: 0, y: 0 },
color: (0, 0, 0), color: (0, 0, 0),
message: "hello world".to_string(), message: String::from("hello world"),
}; };
state.process(Message::ChangeColor(255, 0, 255)); state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Echo(String::from("Hello world!"))); state.process(Message::Echo(String::from("Hello world!")));
state.process(Message::Resize { w: 10, h: 30 }); state.process(Message::Resize { w: 10, h: 30 });
@ -79,7 +75,7 @@ mod tests {
assert_eq!(state.height, 30); assert_eq!(state.height, 30);
assert_eq!(state.position.x, 10); assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15); assert_eq!(state.position.y, 15);
assert_eq!(state.quit, true); assert!(state.quit);
assert_eq!(state.message, "Hello world!"); assert_eq!(state.message, "Hello world!");
} }
} }

View file

@ -1,17 +1,9 @@
// strings1.rs // TODO: Fix the compiler error without changing the function signature.
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() {
let answer = current_favorite_color();
println!("My current favorite color is {}", answer);
}
fn current_favorite_color() -> String { fn current_favorite_color() -> String {
"blue" "blue"
} }
fn main() {
let answer = current_favorite_color();
println!("My current favorite color is {answer}");
}

View file

@ -1,21 +1,14 @@
// strings2.rs // TODO: Fix the compiler error in the `main` function without changing this function.
// fn is_a_color_word(attempt: &str) -> bool {
// Make me compile without changing the function signature! attempt == "green" || attempt == "blue" || attempt == "red"
// }
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
let word = String::from("green"); // Try not changing this line :) let word = String::from("green"); // Don't change this line.
if is_a_color_word(word) { if is_a_color_word(word) {
println!("That is a color word I know!"); println!("That is a color word I know!");
} else { } else {
println!("That is not a color word I know."); println!("That is not a color word I know.");
} }
} }
fn is_a_color_word(attempt: &str) -> bool {
attempt == "green" || attempt == "blue" || attempt == "red"
}

View file

@ -1,23 +1,17 @@
// strings3.rs fn trim_me(input: &str) -> &str {
// // TODO: Remove whitespace from both ends of a string.
// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn trim_me(input: &str) -> String {
// TODO: Remove whitespace from both ends of a string!
???
} }
fn compose_me(input: &str) -> String { fn compose_me(input: &str) -> String {
// TODO: Add " world!" to the string! There's multiple ways to do this! // TODO: Add " world!" to the string! There are multiple ways to do this.
???
} }
fn replace_me(input: &str) -> String { fn replace_me(input: &str) -> String {
// TODO: Replace "cars" in the string with "balloons"! // TODO: Replace "cars" in the string with "balloons".
??? }
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -39,7 +33,13 @@ mod tests {
#[test] #[test]
fn replace_a_string() { fn replace_a_string() {
assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool"); assert_eq!(
assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons"); replace_me("I think cars are cool"),
"I think balloons are cool",
);
assert_eq!(
replace_me("I love to look at cars"),
"I love to look at balloons",
);
} }
} }

View file

@ -1,30 +1,36 @@
// strings4.rs // Calls of this function should be replaced with calls of `string_slice` or `string`.
// fn placeholder() {}
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. 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!
//
// No hints this time!
// I AM NOT DONE
fn string_slice(arg: &str) { fn string_slice(arg: &str) {
println!("{}", arg); println!("{arg}");
} }
fn string(arg: String) { fn string(arg: String) {
println!("{}", arg); println!("{arg}");
} }
// TODO: Here are a bunch of values - some are `String`, some are `&str`.
// Your task is to replace `placeholder(…)` with either `string_slice(…)`
// or `string(…)` depending on what you think each value is.
fn main() { fn main() {
???("blue"); placeholder("blue");
???("red".to_string());
???(String::from("hi")); placeholder("red".to_string());
???("rust is fun!".to_owned());
???("nice weather".into()); placeholder(String::from("hi"));
???(format!("Interpolation {}", "Station"));
???(&String::from("abc")[0..1]); placeholder("rust is fun!".to_owned());
???(" hello there ".trim());
???("Happy Monday!".to_string().replace("Mon", "Tues")); placeholder("nice weather".into());
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
placeholder(format!("Interpolation {}", "Station"));
// WARNING: This is byte indexing, not character indexing.
// Character indexing can be done using `s.chars().nth(INDEX)`.
placeholder(&String::from("abc")[0..1]);
placeholder(" hello there ".trim());
placeholder("Happy Monday!".replace("Mon", "Tues"));
placeholder("mY sHiFt KeY iS sTiCkY".to_lowercase());
} }

View file

@ -1,10 +1,4 @@
// modules1.rs // TODO: Fix the compiler error about calling a private function.
//
// Execute `rustlings hint modules1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
mod sausage_factory { mod sausage_factory {
// Don't let anybody outside of this module see this! // Don't let anybody outside of this module see this!
fn get_secret_recipe() -> String { fn get_secret_recipe() -> String {

View file

@ -1,27 +1,20 @@
// modules2.rs
//
// You can bring module paths into scopes and provide new names for them with // You can bring module paths into scopes and provide new names for them with
// the 'use' and 'as' keywords. Fix these 'use' statements to make the code // the `use` and `as` keywords.
// compile.
//
// Execute `rustlings hint modules2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[allow(dead_code)]
mod delicious_snacks { mod delicious_snacks {
// TODO: Fix these use statements // TODO: Add the following two `use` statements after fixing them.
use self::fruits::PEAR as ??? // use self::fruits::PEAR as ???;
use self::veggies::CUCUMBER as ??? // use self::veggies::CUCUMBER as ???;
mod fruits { mod fruits {
pub const PEAR: &'static str = "Pear"; pub const PEAR: &str = "Pear";
pub const APPLE: &'static str = "Apple"; pub const APPLE: &str = "Apple";
} }
mod veggies { mod veggies {
pub const CUCUMBER: &'static str = "Cucumber"; pub const CUCUMBER: &str = "Cucumber";
pub const CARROT: &'static str = "Carrot"; pub const CARROT: &str = "Carrot";
} }
} }
@ -29,6 +22,6 @@ fn main() {
println!( println!(
"favorite snacks: {} and {}", "favorite snacks: {} and {}",
delicious_snacks::fruit, delicious_snacks::fruit,
delicious_snacks::veggie delicious_snacks::veggie,
); );
} }

View file

@ -1,17 +1,9 @@
// modules3.rs // You can use the `use` keyword to bring module paths from modules from
// // anywhere and especially from the standard library into your scope.
// You can use the 'use' keyword to bring module paths from modules from
// anywhere and especially from the Rust standard library into your scope. Bring
// SystemTime and UNIX_EPOCH from the std::time module. Bonus style points if
// you can do it with one line!
//
// Execute `rustlings hint modules3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE // TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into
// your scope. Bonus style points if you can do it with one line!
// TODO: Complete this use statement // use ???;
use ???
fn main() { fn main() {
match SystemTime::now().duration_since(UNIX_EPOCH) { match SystemTime::now().duration_since(UNIX_EPOCH) {

View file

@ -1,31 +1,27 @@
// hashmaps1.rs
//
// A basket of fruits in the form of a hash map needs to be defined. The key // A basket of fruits in the form of a hash map needs to be defined. The key
// represents the name of the fruit and the value represents how many of that // represents the name of the fruit and the value represents how many of that
// particular fruit is in the basket. You have to put at least three different // particular fruit is in the basket. You have to put at least 3 different
// types of fruits (e.g apple, banana, mango) in the basket and the total count // types of fruits (e.g. apple, banana, mango) in the basket and the total count
// of all the fruits should be at least five. // of all the fruits should be at least 5.
//
// Make me compile and pass the tests!
//
// Execute `rustlings hint hashmaps1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::collections::HashMap; use std::collections::HashMap;
fn fruit_basket() -> HashMap<String, u32> { fn fruit_basket() -> HashMap<String, u32> {
let mut basket = // TODO: declare your hash map here. // TODO: Declare the hash map.
// let mut basket =
// Two bananas are already given for you :) // Two bananas are already given for you :)
basket.insert(String::from("banana"), 2); basket.insert(String::from("banana"), 2);
// TODO: Put more fruits in your basket here. // TODO: Put more fruits in your basket.
basket basket
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -1,5 +1,3 @@
// hashmaps2.rs
//
// We're collecting different fruits to bake a delicious fruit cake. For this, // We're collecting different fruits to bake a delicious fruit cake. For this,
// we have a basket, which we'll represent in the form of a hash map. The key // we have a basket, which we'll represent in the form of a hash map. The key
// represents the name of each fruit we collect and the value represents how // represents the name of each fruit we collect and the value represents how
@ -8,17 +6,10 @@
// must add fruit to the basket so that there is at least one of each kind and // must add fruit to the basket so that there is at least one of each kind and
// more than 11 in total - we have a lot of mouths to feed. You are not allowed // more than 11 in total - we have a lot of mouths to feed. You are not allowed
// to insert any more of these fruits! // to insert any more of these fruits!
//
// Make me pass the tests!
//
// Execute `rustlings hint hashmaps2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Hash, PartialEq, Eq)] #[derive(Hash, PartialEq, Eq, Debug)]
enum Fruit { enum Fruit {
Apple, Apple,
Banana, Banana,
@ -28,7 +19,7 @@ enum Fruit {
} }
fn fruit_basket(basket: &mut HashMap<Fruit, u32>) { fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
let fruit_kinds = vec![ let fruit_kinds = [
Fruit::Apple, Fruit::Apple,
Fruit::Banana, Fruit::Banana,
Fruit::Mango, Fruit::Mango,
@ -43,18 +34,18 @@ fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
// Don't modify this function! // Don't modify this function!
fn get_fruit_basket() -> HashMap<Fruit, u32> { fn get_fruit_basket() -> HashMap<Fruit, u32> {
let mut basket = HashMap::<Fruit, u32>::new(); let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
basket.insert(Fruit::Apple, 4); HashMap::from_iter(content)
basket.insert(Fruit::Mango, 2);
basket.insert(Fruit::Lychee, 5);
basket
} }
#[test] #[test]
@ -84,10 +75,22 @@ mod tests {
#[test] #[test]
fn all_fruit_types_in_basket() { fn all_fruit_types_in_basket() {
let fruit_kinds = [
Fruit::Apple,
Fruit::Banana,
Fruit::Mango,
Fruit::Lychee,
Fruit::Pineapple,
];
let mut basket = get_fruit_basket(); let mut basket = get_fruit_basket();
fruit_basket(&mut basket); fruit_basket(&mut basket);
for amount in basket.values() {
assert_ne!(amount, &0); for fruit_kind in fruit_kinds {
let Some(amount) = basket.get(&fruit_kind) else {
panic!("Fruit kind {fruit_kind:?} was not found in basket");
};
assert!(*amount > 0);
} }
} }
} }

View file

@ -1,86 +1,77 @@
// hashmaps3.rs
//
// A list of scores (one per line) of a soccer match is given. Each line is of // A list of scores (one per line) of a soccer match is given. Each line is of
// the form : "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>" // the form "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
// Example: England,France,4,2 (England scored 4 goals, France 2). // Example: "England,France,4,2" (England scored 4 goals, France 2).
// //
// You have to build a scores table containing the name of the team, goals the // You have to build a scores table containing the name of the team, the total
// team scored, and goals the team conceded. One approach to build the scores // number of goals the team scored, and the total number of goals the team
// table is to use a Hashmap. The solution is partially written to use a // conceded.
// Hashmap, complete it to pass the test.
//
// Make me pass the tests!
//
// Execute `rustlings hint hashmaps3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::collections::HashMap; use std::collections::HashMap;
// A structure to store the goal details of a team. // A structure to store the goal details of a team.
#[derive(Default)]
struct Team { struct Team {
goals_scored: u8, goals_scored: u8,
goals_conceded: u8, goals_conceded: u8,
} }
fn build_scores_table(results: String) -> HashMap<String, Team> { fn build_scores_table(results: &str) -> HashMap<&str, Team> {
// The name of the team is the key and its associated struct is the value. // The name of the team is the key and its associated struct is the value.
let mut scores: HashMap<String, Team> = HashMap::new(); let mut scores = HashMap::new();
for r in results.lines() { for line in results.lines() {
let v: Vec<&str> = r.split(',').collect(); let mut split_iterator = line.split(',');
let team_1_name = v[0].to_string(); // NOTE: We use `unwrap` because we didn't deal with error handling yet.
let team_1_score: u8 = v[2].parse().unwrap(); let team_1_name = split_iterator.next().unwrap();
let team_2_name = v[1].to_string(); let team_2_name = split_iterator.next().unwrap();
let team_2_score: u8 = v[3].parse().unwrap(); let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
// TODO: Populate the scores table with details extracted from the let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
// current line. Keep in mind that goals scored by team_1
// will be the number of goals conceded from team_2, and similarly // TODO: Populate the scores table with the extracted details.
// goals scored by team_2 will be the number of goals conceded by // Keep in mind that goals scored by team 1 will be the number of goals
// team_1. // conceded by team 2. Similarly, goals scored by team 2 will be the
// number of goals conceded by team 1.
} }
scores scores
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
fn get_results() -> String { const RESULTS: &str = "England,France,4,2
let results = "".to_string() France,Italy,3,1
+ "England,France,4,2\n" Poland,Spain,2,0
+ "France,Italy,3,1\n" Germany,England,2,1
+ "Poland,Spain,2,0\n" England,Spain,1,0";
+ "Germany,England,2,1\n";
results
}
#[test] #[test]
fn build_scores() { fn build_scores() {
let scores = build_scores_table(get_results()); let scores = build_scores_table(RESULTS);
let mut keys: Vec<&String> = scores.keys().collect(); assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
keys.sort(); .into_iter()
assert_eq!( .all(|team_name| scores.contains_key(team_name)));
keys,
vec!["England", "France", "Germany", "Italy", "Poland", "Spain"]
);
} }
#[test] #[test]
fn validate_team_score_1() { fn validate_team_score_1() {
let scores = build_scores_table(get_results()); let scores = build_scores_table(RESULTS);
let team = scores.get("England").unwrap(); let team = scores.get("England").unwrap();
assert_eq!(team.goals_scored, 5); assert_eq!(team.goals_scored, 6);
assert_eq!(team.goals_conceded, 4); assert_eq!(team.goals_conceded, 4);
} }
#[test] #[test]
fn validate_team_score_2() { fn validate_team_score_2() {
let scores = build_scores_table(get_results()); let scores = build_scores_table(RESULTS);
let team = scores.get("Spain").unwrap(); let team = scores.get("Spain").unwrap();
assert_eq!(team.goals_scored, 0); assert_eq!(team.goals_scored, 0);
assert_eq!(team.goals_conceded, 2); assert_eq!(team.goals_conceded, 3);
} }
} }

View file

@ -1,19 +1,13 @@
// options1.rs
//
// Execute `rustlings hint options1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
// This function returns how much icecream there is left in the fridge. // This function returns how much icecream there is left in the fridge.
// If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them // If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00,
// all, so there'll be no more left :( // someone eats it all, so no icecream is left (value 0). Return `None` if
fn maybe_icecream(time_of_day: u16) -> Option<u16> { // `hour_of_day` is higher than 23.
// We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a fn maybe_icecream(hour_of_day: u16) -> Option<u16> {
// value of 0 The Option output should gracefully handle cases where // TODO: Complete the function body.
// time_of_day > 23. }
// TODO: Complete the function body - remember to return an Option!
??? fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -21,19 +15,22 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn check_icecream() { fn raw_value() {
assert_eq!(maybe_icecream(9), Some(5)); // TODO: Fix this test. How do you get the value contained in the
assert_eq!(maybe_icecream(10), Some(5)); // Option?
assert_eq!(maybe_icecream(23), Some(0)); let icecreams = maybe_icecream(12);
assert_eq!(maybe_icecream(22), Some(0));
assert_eq!(maybe_icecream(25), None); assert_eq!(icecreams, 5); // Don't change this line.
} }
#[test] #[test]
fn raw_value() { fn check_icecream() {
// TODO: Fix this test. How do you get at the value contained in the assert_eq!(maybe_icecream(0), Some(5));
// Option? assert_eq!(maybe_icecream(9), Some(5));
let icecreams = maybe_icecream(12); assert_eq!(maybe_icecream(18), Some(5));
assert_eq!(icecreams, 5); assert_eq!(maybe_icecream(22), Some(0));
assert_eq!(maybe_icecream(23), Some(0));
assert_eq!(maybe_icecream(24), None);
assert_eq!(maybe_icecream(25), None);
} }
} }

View file

@ -1,9 +1,6 @@
// options2.rs fn main() {
// // You can optionally experiment here.
// Execute `rustlings hint options2` or use the `hint` watch subcommand for a }
// hint.
// I AM NOT DONE
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -12,7 +9,7 @@ mod tests {
let target = "rustlings"; let target = "rustlings";
let optional_target = Some(target); let optional_target = Some(target);
// TODO: Make this an if let statement whose value is "Some" type // TODO: Make this an if-let statement whose value is `Some`.
word = optional_target { word = optional_target {
assert_eq!(word, target); assert_eq!(word, target);
} }
@ -23,15 +20,15 @@ mod tests {
let range = 10; let range = 10;
let mut optional_integers: Vec<Option<i8>> = vec![None]; let mut optional_integers: Vec<Option<i8>> = vec![None];
for i in 1..(range + 1) { for i in 1..=range {
optional_integers.push(Some(i)); optional_integers.push(Some(i));
} }
let mut cursor = range; let mut cursor = range;
// TODO: make this a while let statement - remember that vector.pop also // TODO: Make this a while-let statement. Remember that `Vec::pop()`
// adds another layer of Option<T>. You can stack `Option<T>`s into // adds another layer of `Option`. You can do nested pattern matching
// while let and if let. // in if-let and while-let statements.
integer = optional_integers.pop() { integer = optional_integers.pop() {
assert_eq!(integer, cursor); assert_eq!(integer, cursor);
cursor -= 1; cursor -= 1;

View file

@ -1,21 +1,17 @@
// options3.rs #[derive(Debug)]
//
// Execute `rustlings hint options3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
struct Point { struct Point {
x: i32, x: i32,
y: i32, y: i32,
} }
fn main() { fn main() {
let y: Option<Point> = Some(Point { x: 100, y: 200 }); let optional_point = Some(Point { x: 100, y: 200 });
match y { // TODO: Fix the compiler error by adding something to this match statement.
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y), match optional_point {
_ => panic!("no match!"), Some(p) => println!("Co-ordinates are {},{}", p.x, p.y),
_ => panic!("No match!"),
} }
y; // Fix without deleting this line.
println!("{optional_point:?}"); // Don't change this line.
} }

View file

@ -1,25 +1,22 @@
// errors1.rs // TODO: 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
// This function refuses to generate text to be printed on a nametag if you pass // was instead of just returning `None`. Thankfully, Rust has a similar
// it an empty string. It'd be nicer if it explained what the problem was, // construct to `Option` that can be used to express error conditions. Change
// instead of just sometimes returning `None`. Thankfully, Rust has a similar // the function signature and body to return `Result<String, String>` instead
// construct to `Option` that can be used to express error conditions. Let's use // of `Option<String>`.
// it! fn generate_nametag_text(name: String) -> Option<String> {
//
// Execute `rustlings hint errors1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
pub fn generate_nametag_text(name: String) -> Option<String> {
if name.is_empty() { if name.is_empty() {
// Empty names aren't allowed. // Empty names aren't allowed.
None None
} else { } else {
Some(format!("Hi! My name is {}", name)) Some(format!("Hi! My name is {name}"))
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -27,17 +24,18 @@ mod tests {
#[test] #[test]
fn generates_nametag_text_for_a_nonempty_name() { fn generates_nametag_text_for_a_nonempty_name() {
assert_eq!( assert_eq!(
generate_nametag_text("Beyoncé".into()), generate_nametag_text("Beyoncé".to_string()).as_deref(),
Ok("Hi! My name is Beyoncé".into()) Ok("Hi! My name is Beyoncé"),
); );
} }
#[test] #[test]
fn explains_why_generating_nametag_text_fails() { fn explains_why_generating_nametag_text_fails() {
assert_eq!( assert_eq!(
generate_nametag_text("".into()), generate_nametag_text(String::new())
// Don't change this line .as_ref()
Err("`name` was empty; it must be nonempty.".into()) .map_err(|e| e.as_str()),
Err("Empty names aren't allowed"),
); );
} }
} }

View file

@ -1,39 +1,39 @@
// errors2.rs
//
// Say we're writing a game where you can buy items with tokens. All items cost // 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 // 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 // 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 cost of the items. Since // the `total_cost` function will calculate the total cost of the items. Since
// the player typed in the quantity, though, we get it as a string-- and they // the player typed in the quantity, we get it as a string. They might have
// might have typed anything, not just numbers! // typed anything, not just numbers!
// //
// Right now, this function isn't handling the error case at all (and isn't // Right now, this function isn't handling the error case at all. What we want
// handling the success case properly either). What we want to do is: if we call // to do is: If we call the `total_cost` function on a string that is not a
// the `total_cost` function on a string that is not a number, that function // number, that function will return a `ParseIntError`. In that case, we want to
// will return a `ParseIntError`, and in that case, we want to immediately // immediately return that error from our function and not try to multiply and
// return that error from our function and not try to multiply and add. // add.
// //
// There are at least two ways to implement this that are both correct-- but one // There are at least two ways to implement this that are both correct. But one
// is a lot shorter! // is a lot shorter!
//
// Execute `rustlings hint errors2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::num::ParseIntError; use std::num::ParseIntError;
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> { fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1; let processing_fee = 1;
let cost_per_item = 5; let cost_per_item = 5;
// TODO: Handle the error case as described above.
let qty = item_quantity.parse::<i32>(); let qty = item_quantity.parse::<i32>();
Ok(qty * cost_per_item + processing_fee) Ok(qty * cost_per_item + processing_fee)
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::num::IntErrorKind;
#[test] #[test]
fn item_quantity_is_a_valid_number() { fn item_quantity_is_a_valid_number() {
@ -43,8 +43,8 @@ mod tests {
#[test] #[test]
fn item_quantity_is_an_invalid_number() { fn item_quantity_is_an_invalid_number() {
assert_eq!( assert_eq!(
total_cost("beep boop").unwrap_err().to_string(), total_cost("beep boop").unwrap_err().kind(),
"invalid digit found in string" &IntErrorKind::InvalidDigit,
); );
} }
} }

View file

@ -1,16 +1,20 @@
// errors3.rs
//
// This is a program that is trying to use a completed version of the // 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! // `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it? // Why not? What should we do to fix it?
//
// Execute `rustlings hint errors3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::num::ParseIntError; use std::num::ParseIntError;
// Don't change this function.
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)
}
// TODO: Fix the compiler error by changing the signature and body of the
// `main` function.
fn main() { fn main() {
let mut tokens = 100; let mut tokens = 100;
let pretend_user_input = "8"; let pretend_user_input = "8";
@ -21,14 +25,6 @@ fn main() {
println!("You can't afford that many!"); println!("You can't afford that many!");
} else { } else {
tokens -= cost; tokens -= cost;
println!("You now have {} tokens.", tokens); 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)
}

View file

@ -1,12 +1,4 @@
// errors4.rs #![allow(clippy::comparison_chain)]
//
// Execute `rustlings hint errors4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
enum CreationError { enum CreationError {
@ -14,19 +6,34 @@ enum CreationError {
Zero, Zero,
} }
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
impl PositiveNonzeroInteger { impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { fn new(value: i64) -> Result<Self, CreationError> {
// Hmm... Why is this always returning an Ok value? // TODO: This function shouldn't always return an `Ok`.
Ok(PositiveNonzeroInteger(value as u64)) Ok(Self(value as u64))
} }
} }
#[test] fn main() {
fn test_creation() { // You can optionally experiment here.
assert!(PositiveNonzeroInteger::new(10).is_ok()); }
assert_eq!(
Err(CreationError::Negative), #[cfg(test)]
PositiveNonzeroInteger::new(-10) mod tests {
); use super::*;
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
#[test]
fn test_creation() {
assert_eq!(
PositiveNonzeroInteger::new(10),
Ok(PositiveNonzeroInteger(10)),
);
assert_eq!(
PositiveNonzeroInteger::new(-10),
Err(CreationError::Negative),
);
assert_eq!(PositiveNonzeroInteger::new(0), Err(CreationError::Zero));
}
} }

View file

@ -1,45 +1,18 @@
// errors5.rs // This exercise is an altered version of the `errors4` exercise. It uses some
// // concepts that we won't get to until later in the course, like `Box` and the
// This program uses an altered version of the code from errors4. // `From` trait. It's not important to understand them in detail right now, but
// // you can read ahead if you like. For now, think of the `Box<dyn ???>` type as
// This exercise uses some concepts that we won't get to until later in the // an "I want anything that does ???" type.
// 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. For now, think
// of the `Box<dyn ???>` type as an "I want anything that does ???" type, which,
// given Rust's usual standards for runtime safety, should strike you as
// somewhat lenient!
// //
// In short, this particular use case for boxes is for when you want to own a // In short, this particular use case for boxes is for when you want to own a
// value and you care only that it is a type which implements a particular // value and you care only that it is a type which implements a particular
// trait. To do so, The Box is declared as of type Box<dyn Trait> where Trait is // trait. To do so, The `Box` is declared as of type `Box<dyn Trait>` where
// the trait the compiler looks for on any value used in that context. For this // `Trait` is the trait the compiler looks for on any value used in that
// exercise, that context is the potential errors which can be returned in a // context. For this exercise, that context is the potential errors which
// Result. // can be returned in a `Result`.
//
// What can we use to describe both errors? In other words, is there a trait
// which both errors implement?
//
// Execute `rustlings hint errors5` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE use std::error::Error;
use std::error;
use std::fmt; use std::fmt;
use std::num::ParseIntError;
// TODO: update the return type of `main()` to make this compile.
fn main() -> Result<(), Box<dyn ???>> {
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)] #[derive(PartialEq, Debug)]
enum CreationError { enum CreationError {
@ -47,17 +20,7 @@ enum CreationError {
Zero, Zero,
} }
impl PositiveNonzeroInteger { // This is required so that `CreationError` can implement `Error`.
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 { impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let description = match *self { let description = match *self {
@ -68,4 +31,26 @@ impl fmt::Display for CreationError {
} }
} }
impl error::Error for CreationError {} impl Error for CreationError {}
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
match value {
0 => Err(CreationError::Zero),
x if x < 0 => Err(CreationError::Negative),
x => Ok(PositiveNonzeroInteger(x as u64)),
}
}
}
// TODO: Add the correct return type `Result<(), Box<dyn ???>>`. What can we
// use to describe both errors? Is there a trait which both errors implement?
fn main() {
let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?;
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
Ok(())
}

View file

@ -1,59 +1,55 @@
// errors6.rs // Using catch-all error types like `Box<dyn Error>` isn't recommended for
// // library code where callers might want to make decisions based on the error
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended // content instead of printing it out or propagating it further. Here, we define
// for library code, where callers might want to make decisions based on the // a custom error type to make it possible for callers to decide what to do next
// error content, instead of printing it out or propagating it further. Here, we // when our function returns an error.
// define a custom error type to make it possible for callers to decide what to
// do next when our function returns an error.
//
// Execute `rustlings hint errors6` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::num::ParseIntError; 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 from_parseint...
}
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)] #[derive(PartialEq, Debug)]
enum CreationError { enum CreationError {
Negative, Negative,
Zero, Zero,
} }
// A custom error type that we will be using in `PositiveNonzeroInteger::parse`.
#[derive(PartialEq, Debug)]
enum ParsePosNonzeroError {
Creation(CreationError),
ParseInt(ParseIntError),
}
impl ParsePosNonzeroError {
fn from_creation(err: CreationError) -> Self {
Self::Creation(err)
}
// TODO: Add another error conversion function here.
// fn from_parseint(???) -> Self { ??? }
}
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
impl PositiveNonzeroInteger { impl PositiveNonzeroInteger {
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { fn new(value: i64) -> Result<Self, CreationError> {
match value { match value {
x if x < 0 => Err(CreationError::Negative), x if x < 0 => Err(CreationError::Negative),
x if x == 0 => Err(CreationError::Zero), 0 => Err(CreationError::Zero),
x => Ok(PositiveNonzeroInteger(x as u64)), x => Ok(Self(x as u64)),
} }
} }
fn parse(s: &str) -> Result<Self, ParsePosNonzeroError> {
// TODO: change this to return an appropriate error instead of panicking
// when `parse()` returns an error.
let x: i64 = s.parse().unwrap();
Self::new(x).map_err(ParsePosNonzeroError::from_creation)
}
}
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -62,33 +58,32 @@ mod test {
#[test] #[test]
fn test_parse_error() { fn test_parse_error() {
// We can't construct a ParseIntError, so we have to pattern match.
assert!(matches!( assert!(matches!(
parse_pos_nonzero("not a number"), PositiveNonzeroInteger::parse("not a number"),
Err(ParsePosNonzeroError::ParseInt(_)) Err(ParsePosNonzeroError::ParseInt(_)),
)); ));
} }
#[test] #[test]
fn test_negative() { fn test_negative() {
assert_eq!( assert_eq!(
parse_pos_nonzero("-555"), PositiveNonzeroInteger::parse("-555"),
Err(ParsePosNonzeroError::Creation(CreationError::Negative)) Err(ParsePosNonzeroError::Creation(CreationError::Negative)),
); );
} }
#[test] #[test]
fn test_zero() { fn test_zero() {
assert_eq!( assert_eq!(
parse_pos_nonzero("0"), PositiveNonzeroInteger::parse("0"),
Err(ParsePosNonzeroError::Creation(CreationError::Zero)) Err(ParsePosNonzeroError::Creation(CreationError::Zero)),
); );
} }
#[test] #[test]
fn test_positive() { fn test_positive() {
let x = PositiveNonzeroInteger::new(42); let x = PositiveNonzeroInteger::new(42).unwrap();
assert!(x.is_ok()); assert_eq!(x.0, 42);
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap())); assert_eq!(PositiveNonzeroInteger::parse("42"), Ok(x));
} }
} }

View file

@ -1,7 +1,7 @@
# Generics # Generics
Generics is the topic of generalizing types and functionalities to broader cases. Generics is the topic of generalizing types and functionalities to broader cases.
This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax. This is extremely useful for reducing code duplication in many ways, but can call for some rather involved syntax.
Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid. Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
The simplest and most common use of generics is for type parameters. The simplest and most common use of generics is for type parameters.

View file

@ -1,14 +1,18 @@
// generics1.rs // `Vec<T>` is generic over the type `T`. In most cases, the compiler is able to
// // infer `T`, for example after pushing a value with a concrete type to the vector.
// This shopping list program isn't compiling! Use your knowledge of generics to // But in this exercise, the compiler needs some help through a type annotation.
// fix it.
//
// Execute `rustlings hint generics1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn main() { fn main() {
let mut shopping_list: Vec<?> = Vec::new(); // TODO: Fix the compiler error by annotating the type of the vector
shopping_list.push("milk"); // `Vec<T>`. Choose `T` as some integer type that can be created from
// `u8` and `i8`.
let mut numbers = Vec::new();
// Don't change the lines below.
let n1: u8 = 42;
numbers.push(n1.into());
let n2: i8 = -1;
numbers.push(n2.into());
println!("{numbers:?}");
} }

View file

@ -1,23 +1,20 @@
// generics2.rs
//
// This powerful wrapper provides the ability to store a positive integer value. // This powerful wrapper provides the ability to store a positive integer value.
// Rewrite it using generics so that it supports wrapping ANY type. // TODO: Rewrite it using a generic so that it supports wrapping ANY type.
//
// Execute `rustlings hint generics2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
struct Wrapper { struct Wrapper {
value: u32, value: u32,
} }
// TODO: Adapt the struct's implementation to be generic over the wrapped value.
impl Wrapper { impl Wrapper {
pub fn new(value: u32) -> Self { fn new(value: u32) -> Self {
Wrapper { value } Wrapper { value }
} }
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -1,26 +1,17 @@
// traits1.rs // The trait `AppendBar` has only one function which appends "Bar" to any object
// // implementing this trait.
// Time to implement some traits! Your task is to implement the trait
// `AppendBar` for the type `String`. The trait AppendBar has only one function,
// which appends "Bar" to any object implementing this trait.
//
// Execute `rustlings hint traits1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
trait AppendBar { trait AppendBar {
fn append_bar(self) -> Self; fn append_bar(self) -> Self;
} }
impl AppendBar for String { impl AppendBar for String {
// TODO: Implement `AppendBar` for type `String`. // TODO: Implement `AppendBar` for the type `String`.
} }
fn main() { fn main() {
let s = String::from("Foo"); let s = String::from("Foo");
let s = s.append_bar(); let s = s.append_bar();
println!("s: {}", s); println!("s: {s}");
} }
#[cfg(test)] #[cfg(test)]
@ -29,14 +20,11 @@ mod tests {
#[test] #[test]
fn is_foo_bar() { fn is_foo_bar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar")); assert_eq!(String::from("Foo").append_bar(), "FooBar");
} }
#[test] #[test]
fn is_bar_bar() { fn is_bar_bar() {
assert_eq!( assert_eq!(String::from("").append_bar().append_bar(), "BarBar");
String::from("").append_bar().append_bar(),
String::from("BarBar")
);
} }
} }

View file

@ -1,20 +1,13 @@
// traits2.rs
//
// Your task is to implement the trait `AppendBar` for a vector of strings. To
// implement this trait, consider for a moment what it means to 'append "Bar"'
// to a vector of strings.
//
// No boiler plate code this time, you can do this!
//
// Execute `rustlings hint traits2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
trait AppendBar { trait AppendBar {
fn append_bar(self) -> Self; fn append_bar(self) -> Self;
} }
// TODO: Implement trait `AppendBar` for a vector of strings. // TODO: Implement the trait `AppendBar` for a vector of strings.
// `append_bar` should push the string "Bar" into the vector.
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -23,7 +16,7 @@ mod tests {
#[test] #[test]
fn is_vec_pop_eq_bar() { fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar(); let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar")); assert_eq!(foo.pop().unwrap(), "Bar");
assert_eq!(foo.pop().unwrap(), String::from("Foo")); assert_eq!(foo.pop().unwrap(), "Foo");
} }
} }

View file

@ -1,16 +1,10 @@
// traits3.rs #![allow(dead_code)]
//
// Your task is to implement the Licensed trait for both structures and have
// them return the same information without writing the same function twice.
//
// Consider what you can add to the Licensed trait.
//
// Execute `rustlings hint traits3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE trait Licensed {
// TODO: Add a default implementation for `licensing_info` so that
pub trait Licensed { // implementors like the two structs below can share that default behavior
// without repeating the function.
// The default license information should be the string "Default license".
fn licensing_info(&self) -> String; fn licensing_info(&self) -> String;
} }
@ -22,8 +16,12 @@ struct OtherSoftware {
version_number: String, version_number: String,
} }
impl Licensed for SomeSoftware {} // Don't edit this line impl Licensed for SomeSoftware {} // Don't edit this line.
impl Licensed for OtherSoftware {} // Don't edit this line impl Licensed for OtherSoftware {} // Don't edit this line.
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -31,7 +29,7 @@ mod tests {
#[test] #[test]
fn is_licensing_info_the_same() { fn is_licensing_info_the_same() {
let licensing_info = String::from("Some information"); let licensing_info = "Default license";
let some_software = SomeSoftware { version_number: 1 }; let some_software = SomeSoftware { version_number: 1 };
let other_software = OtherSoftware { let other_software = OtherSoftware {
version_number: "v2.0.0".to_string(), version_number: "v2.0.0".to_string(),

View file

@ -1,30 +1,22 @@
// traits4.rs trait Licensed {
//
// Your task is to replace the '??' sections so the code compiles.
//
// Don't change any line other than the marked one.
//
// Execute `rustlings hint traits4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
pub trait Licensed {
fn licensing_info(&self) -> String { fn licensing_info(&self) -> String {
"some information".to_string() "Default license".to_string()
} }
} }
struct SomeSoftware {} struct SomeSoftware;
struct OtherSoftware;
struct OtherSoftware {}
impl Licensed for SomeSoftware {} impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {} impl Licensed for OtherSoftware {}
// YOU MAY ONLY CHANGE THE NEXT LINE // TODO: Fix the compiler error by only changing the signature of this function.
fn compare_license_types(software: ??, software_two: ??) -> bool { fn compare_license_types(software1: ???, software2: ???) -> bool {
software.licensing_info() == software_two.licensing_info() software1.licensing_info() == software2.licensing_info()
}
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -33,17 +25,11 @@ mod tests {
#[test] #[test]
fn compare_license_information() { fn compare_license_information() {
let some_software = SomeSoftware {}; assert!(compare_license_types(SomeSoftware, OtherSoftware));
let other_software = OtherSoftware {};
assert!(compare_license_types(some_software, other_software));
} }
#[test] #[test]
fn compare_license_information_backwards() { fn compare_license_information_backwards() {
let some_software = SomeSoftware {}; assert!(compare_license_types(OtherSoftware, SomeSoftware));
let other_software = OtherSoftware {};
assert!(compare_license_types(other_software, some_software));
} }
} }

View file

@ -1,40 +1,39 @@
// traits5.rs trait SomeTrait {
//
// Your task is to replace the '??' sections so the code compiles.
//
// Don't change any line other than the marked one.
//
// Execute `rustlings hint traits5` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
pub trait SomeTrait {
fn some_function(&self) -> bool { fn some_function(&self) -> bool {
true true
} }
} }
pub trait OtherTrait { trait OtherTrait {
fn other_function(&self) -> bool { fn other_function(&self) -> bool {
true true
} }
} }
struct SomeStruct {} struct SomeStruct;
struct OtherStruct {}
impl SomeTrait for SomeStruct {} impl SomeTrait for SomeStruct {}
impl OtherTrait for SomeStruct {} impl OtherTrait for SomeStruct {}
struct OtherStruct;
impl SomeTrait for OtherStruct {} impl SomeTrait for OtherStruct {}
impl OtherTrait for OtherStruct {} impl OtherTrait for OtherStruct {}
// YOU MAY ONLY CHANGE THE NEXT LINE // TODO: Fix the compiler error by only changing the signature of this function.
fn some_func(item: ??) -> bool { fn some_func(item: ???) -> bool {
item.some_function() && item.other_function() item.some_function() && item.other_function()
} }
fn main() { fn main() {
some_func(SomeStruct {}); // You can optionally experiment here.
some_func(OtherStruct {}); }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_some_func() {
assert!(some_func(SomeStruct));
assert!(some_func(OtherStruct));
}
} }

View file

@ -1,15 +1,9 @@
// lifetimes1.rs
//
// The Rust compiler needs to know how to check whether supplied references are // The Rust compiler needs to know how to check whether supplied references are
// valid, so that it can let the programmer know if a reference is at risk of // valid, so that it can let the programmer know if a reference is at risk of
// going out of scope before it is used. Remember, references are borrows and do // going out of scope before it is used. Remember, references are borrows and do
// not own their own data. What if their owner goes out of scope? // not own their own data. What if their owner goes out of scope?
//
// Execute `rustlings hint lifetimes1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
// TODO: Fix the compiler error by updating the function signature.
fn longest(x: &str, y: &str) -> &str { fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() { if x.len() > y.len() {
x x
@ -19,9 +13,16 @@ fn longest(x: &str, y: &str) -> &str {
} }
fn main() { fn main() {
let string1 = String::from("abcd"); // You can optionally experiment here.
let string2 = "xyz"; }
let result = longest(string1.as_str(), string2); #[cfg(test)]
println!("The longest string is '{}'", result); mod tests {
use super::*;
#[test]
fn test_longest() {
assert_eq!(longest("abcd", "123"), "abcd");
assert_eq!(longest("abc", "1234"), "1234");
}
} }

View file

@ -1,13 +1,4 @@
// lifetimes2.rs // Don't change this function.
//
// So if the compiler is just validating the references passed to the annotated
// parameters and the return type, what do we need to change?
//
// Execute `rustlings hint lifetimes2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { if x.len() > y.len() {
x x
@ -17,11 +8,13 @@ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
} }
fn main() { fn main() {
// TODO: Fix the compiler error by moving one line.
let string1 = String::from("long string is long"); let string1 = String::from("long string is long");
let result; let result;
{ {
let string2 = String::from("xyz"); let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str()); result = longest(&string1, &string2);
} }
println!("The longest string is '{}'", result); println!("The longest string is '{result}'");
} }

View file

@ -1,21 +1,16 @@
// lifetimes3.rs
//
// Lifetimes are also needed when structs hold references. // Lifetimes are also needed when structs hold references.
//
// Execute `rustlings hint lifetimes3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
// TODO: Fix the compiler errors about the struct.
struct Book { struct Book {
author: &str, author: &str,
title: &str, title: &str,
} }
fn main() { fn main() {
let name = String::from("Jill Smith"); let book = Book {
let title = String::from("Fish Flying"); author: "George Orwell",
let book = Book { author: &name, title: &title }; title: "1984",
};
println!("{} by {}", book.title, book.author); println!("{} by {}", book.title, book.author);
} }

View file

@ -1,21 +1,23 @@
// tests1.rs
//
// Tests are important to ensure that your code does what you think it should // 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: rustlings run // do.
// tests1
//
// This test has a problem with it -- make the test compile! Make the test pass!
// Make the test fail!
//
// Execute `rustlings hint tests1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE fn is_even(n: i64) -> bool {
n % 2 == 0
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
// TODO: Import `is_even`. You can use a wildcard to import everything in
// the outer module.
#[test] #[test]
fn you_can_assert() { fn you_can_assert() {
// TODO: Test the function `is_even` with some values.
assert!();
assert!(); assert!();
} }
} }

View file

@ -1,17 +1,23 @@
// tests2.rs // Calculates the power of 2 using a bit shift.
// // `1 << n` is equivalent to "2 to the power of n".
// This test has a problem with it -- make the test compile! Make the test pass! fn power_of_2(n: u8) -> u64 {
// Make the test fail! 1 << n
// }
// Execute `rustlings hint tests2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
#[test] #[test]
fn you_can_assert_eq() { fn you_can_assert_eq() {
// TODO: Test the function `power_of_2` with some values.
assert_eq!();
assert_eq!();
assert_eq!();
assert_eq!(); assert_eq!();
} }
} }

View file

@ -1,16 +1,23 @@
// tests3.rs struct Rectangle {
// width: i32,
// This test isn't testing our function -- make it do that in such a way that height: i32,
// the test passes. Then write a second test that tests whether we get the }
// result we expect to get when we call `is_even(5)`.
//
// Execute `rustlings hint tests3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE impl Rectangle {
// Don't change this function.
fn new(width: i32, height: i32) -> Self {
if width <= 0 || height <= 0 {
// Returning a `Result` would be better here. But we want to learn
// how to test functions that can panic.
panic!("Rectangle width and height can't be negative");
}
pub fn is_even(num: i32) -> bool { Rectangle { width, height }
num % 2 == 0 }
}
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -18,12 +25,25 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn is_true_when_even() { fn correct_width_and_height() {
assert!(); // TODO: This test should check if the rectangle has the size that we
// pass to its constructor.
let rect = Rectangle::new(10, 20);
assert_eq!(todo!(), 10); // Check width
assert_eq!(todo!(), 20); // Check height
} }
// TODO: This test should check if the program panics when we try to create
// a rectangle with negative width.
#[test] #[test]
fn is_false_when_odd() { fn negative_width() {
assert!(); let _rect = Rectangle::new(-10, 10);
}
// TODO: This test should check if the program panics when we try to create
// a rectangle with negative height.
#[test]
fn negative_height() {
let _rect = Rectangle::new(10, -10);
} }
} }

View file

@ -1,48 +0,0 @@
// tests4.rs
//
// Make sure that we're testing for the correct conditions!
//
// Execute `rustlings hint tests4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
struct Rectangle {
width: i32,
height: i32
}
impl Rectangle {
// Only change the test functions themselves
pub fn new(width: i32, height: i32) -> Self {
if width <= 0 || height <= 0 {
panic!("Rectangle width and height cannot be negative!")
}
Rectangle {width, height}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn correct_width_and_height() {
// This test should check if the rectangle is the size that we pass into its constructor
let rect = Rectangle::new(10, 20);
assert_eq!(???, 10); // check width
assert_eq!(???, 20); // check height
}
#[test]
fn negative_width() {
// This test should check if program panics when we try to create rectangle with negative width
let _rect = Rectangle::new(-10, 10);
}
#[test]
fn negative_height() {
// This test should check if program panics when we try to create rectangle with negative height
let _rect = Rectangle::new(10, -10);
}
}

View file

@ -1,26 +1,25 @@
// iterators1.rs
//
// When performing operations on elements within a collection, iterators are // When performing operations on elements within a collection, iterators are
// essential. This module helps you get familiar with the structure of using an // essential. This module helps you get familiar with the structure of using an
// iterator and how to go through elements within an iterable collection. // iterator and how to go through elements within an iterable collection.
//
// Make me compile by filling in the `???`s
//
// Execute `rustlings hint iterators1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[test]
fn main() { fn main() {
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; // You can optionally experiment here.
}
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
#[cfg(test)]
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana")); mod tests {
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2 #[test]
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado")); fn iterators() {
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3 let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"];
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 4 // TODO: Create an iterator over the array.
let mut fav_fruits_iterator = todo!();
assert_eq!(fav_fruits_iterator.next(), Some(&"banana"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"avocado"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry"));
assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()`
}
} }

View file

@ -1,38 +1,32 @@
// iterators2.rs
//
// In this exercise, you'll learn some of the unique advantages that iterators // In this exercise, you'll learn some of the unique advantages that iterators
// can offer. Follow the steps to complete the exercise. // can offer.
//
// Execute `rustlings hint iterators2` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE // TODO: Complete the `capitalize_first` function.
// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello" // "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String { fn capitalize_first(input: &str) -> String {
let mut c = input.chars(); let mut chars = input.chars();
match c.next() { match chars.next() {
None => String::new(), None => String::new(),
Some(first) => ???, Some(first) => todo!(),
} }
} }
// Step 2. // TODO: Apply the `capitalize_first` function to a slice of string slices.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings. // Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"] // ["hello", "world"] -> ["Hello", "World"]
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> { fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
vec![] // ???
} }
// Step 3. // TODO: Apply the `capitalize_first` function again to a slice of string
// Apply the `capitalize_first` function again to a slice of string slices. // slices. Return a single string.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World" // ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String { fn capitalize_words_string(words: &[&str]) -> String {
String::new() // ???
}
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,50 +1,33 @@
// iterators3.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. Get the remaining tests to pass by completing the result_with_list and
// list_of_results functions.
//
// Execute `rustlings hint iterators3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum DivisionError { enum DivisionError {
NotDivisible(NotDivisibleError),
DivideByZero, DivideByZero,
NotDivisible,
} }
#[derive(Debug, PartialEq, Eq)] // TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
pub struct NotDivisibleError {
dividend: i32,
divisor: i32,
}
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error. // Otherwise, return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> { fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
todo!(); todo!();
} }
// Complete the function and return a value of the correct type so the test // TODO: Add the correct return type and complete the function body.
// passes. // Desired output: `Ok([1, 11, 1426, 3])`
// Desired output: Ok([1, 11, 1426, 3]) fn result_with_list() {
fn result_with_list() -> () { let numbers = [27, 297, 38502, 81];
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let division_results = numbers.into_iter().map(|n| divide(n, 27));
} }
// Complete the function and return a value of the correct type so the test // TODO: Add the correct return type and complete the function body.
// passes. // Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]`
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)] fn list_of_results() {
fn list_of_results() -> () { let numbers = [27, 297, 38502, 81];
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27)); let division_results = numbers.into_iter().map(|n| divide(n, 27));
} }
fn main() {
// You can optionally experiment here.
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -55,19 +38,13 @@ mod tests {
} }
#[test] #[test]
fn test_not_divisible() { fn test_divide_by_0() {
assert_eq!( assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
divide(81, 6),
Err(DivisionError::NotDivisible(NotDivisibleError {
dividend: 81,
divisor: 6
}))
);
} }
#[test] #[test]
fn test_divide_by_0() { fn test_not_divisible() {
assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); assert_eq!(divide(81, 6), Err(DivisionError::NotDivisible));
} }
#[test] #[test]
@ -77,14 +54,11 @@ mod tests {
#[test] #[test]
fn test_result_with_list() { fn test_result_with_list() {
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])"); assert_eq!(result_with_list().unwrap(), [1, 11, 1426, 3]);
} }
#[test] #[test]
fn test_list_of_results() { fn test_list_of_results() {
assert_eq!( assert_eq!(list_of_results(), [Ok(1), Ok(11), Ok(1426), Ok(3)]);
format!("{:?}", list_of_results()),
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
);
} }
} }

View file

@ -1,20 +1,16 @@
// iterators4.rs fn factorial(num: u64) -> u64 {
// // TODO: Complete this function to return the factorial of `num`.
// Execute `rustlings hint iterators4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
pub fn factorial(num: u64) -> u64 {
// Complete this function to return the factorial of num
// Do not use: // Do not use:
// - return // - early returns (using the `return` keyword explicitly)
// Try not to use: // Try not to use:
// - imperative style loops (for, while) // - imperative style loops (for/while)
// - additional variables // - additional variables
// For an extra challenge, don't use: // For an extra challenge, don't use:
// - recursion // - recursion
// Execute `rustlings hint iterators4` for hints. }
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -23,20 +19,20 @@ mod tests {
#[test] #[test]
fn factorial_of_0() { fn factorial_of_0() {
assert_eq!(1, factorial(0)); assert_eq!(factorial(0), 1);
} }
#[test] #[test]
fn factorial_of_1() { fn factorial_of_1() {
assert_eq!(1, factorial(1)); assert_eq!(factorial(1), 1);
} }
#[test] #[test]
fn factorial_of_2() { fn factorial_of_2() {
assert_eq!(2, factorial(2)); assert_eq!(factorial(2), 2);
} }
#[test] #[test]
fn factorial_of_4() { fn factorial_of_4() {
assert_eq!(24, factorial(4)); assert_eq!(factorial(4), 24);
} }
} }

View file

@ -1,17 +1,8 @@
// iterators5.rs // Let's define a simple model to track Rustlings' exercise progress. Progress
//
// Let's define a simple model to track Rustlings exercise progress. Progress
// will be modelled using a hash map. The name of the exercise is the key and // will be modelled using a hash map. The name of the exercise is the key and
// the progress is the value. Two counting functions were created to count the // the progress is the value. Two counting functions were created to count the
// number of exercises with a given progress. Recreate this counting // number of exercises with a given progress. Recreate this counting
// functionality using iterators. Try not to use imperative loops (for, while). // functionality using iterators. Try to not use imperative loops (for/while).
// Only the two iterator methods (count_iterator and count_collection_iterator)
// need to be modified.
//
// Execute `rustlings hint iterators5` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
use std::collections::HashMap; use std::collections::HashMap;
@ -25,24 +16,25 @@ enum Progress {
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize { fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
let mut count = 0; let mut count = 0;
for val in map.values() { for val in map.values() {
if val == &value { if *val == value {
count += 1; count += 1;
} }
} }
count count
} }
// TODO: Implement the functionality of `count_for` but with an iterator instead
// of a `for` loop.
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize { fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
// map is a hashmap with String keys and Progress values. // `map` is a hash map with `String` keys and `Progress` values.
// map = { "variables1": Complete, "from_str": None, ... } // map = { "variables1": Complete, "from_str": None, … }
todo!();
} }
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize { fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
let mut count = 0; let mut count = 0;
for map in collection { for map in collection {
for val in map.values() { for val in map.values() {
if val == &value { if *val == value {
count += 1; count += 1;
} }
} }
@ -50,81 +42,22 @@ fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progres
count count
} }
// TODO: Implement the functionality of `count_collection_for` but with an
// iterator instead of a `for` loop.
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize { fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
// collection is a slice of hashmaps. // `collection` is a slice of hash maps.
// collection = [{ "variables1": Complete, "from_str": None, ... }, // collection = [{ "variables1": Complete, "from_str": None, … },
// { "variables2": Complete, ... }, ... ] // { "variables2": Complete, … }, … ]
todo!(); }
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(3, count_iterator(&map, Progress::Complete));
}
#[test]
fn count_some() {
let map = get_map();
assert_eq!(1, count_iterator(&map, Progress::Some));
}
#[test]
fn count_none() {
let map = get_map();
assert_eq!(2, count_iterator(&map, Progress::None));
}
#[test]
fn count_complete_equals_for() {
let map = get_map();
let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_for(&map, progress_state),
count_iterator(&map, progress_state)
);
}
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
6,
count_collection_iterator(&collection, Progress::Complete)
);
}
#[test]
fn count_collection_some() {
let collection = get_vec_map();
assert_eq!(1, count_collection_iterator(&collection, Progress::Some));
}
#[test]
fn count_collection_none() {
let collection = get_vec_map();
assert_eq!(4, count_collection_iterator(&collection, Progress::None));
}
#[test]
fn count_collection_equals_for() {
let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
let collection = get_vec_map();
for progress_state in progress_states {
assert_eq!(
count_collection_for(&collection, progress_state),
count_collection_iterator(&collection, progress_state)
);
}
}
fn get_map() -> HashMap<String, Progress> { fn get_map() -> HashMap<String, Progress> {
use Progress::*; use Progress::*;
@ -153,4 +86,68 @@ mod tests {
vec![map, other] vec![map, other]
} }
#[test]
fn count_complete() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Complete), 3);
}
#[test]
fn count_some() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::Some), 1);
}
#[test]
fn count_none() {
let map = get_map();
assert_eq!(count_iterator(&map, Progress::None), 2);
}
#[test]
fn count_complete_equals_for() {
let map = get_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_for(&map, progress_state),
count_iterator(&map, progress_state),
);
}
}
#[test]
fn count_collection_complete() {
let collection = get_vec_map();
assert_eq!(
count_collection_iterator(&collection, Progress::Complete),
6,
);
}
#[test]
fn count_collection_some() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::Some), 1);
}
#[test]
fn count_collection_none() {
let collection = get_vec_map();
assert_eq!(count_collection_iterator(&collection, Progress::None), 4);
}
#[test]
fn count_collection_equals_for() {
let collection = get_vec_map();
let progress_states = [Progress::Complete, Progress::Some, Progress::None];
for progress_state in progress_states {
assert_eq!(
count_collection_for(&collection, progress_state),
count_collection_iterator(&collection, progress_state),
);
}
}
} }

View file

@ -1,45 +1,45 @@
// arc1.rs // In this exercise, we are given a `Vec` of `u32` called `numbers` with values
// ranging from 0 to 99. We would like to use this set of numbers within 8
// different threads simultaneously. Each thread is going to get the sum of
// every eighth value with an offset.
// //
// In this exercise, we are given a Vec of u32 called "numbers" with values // The first thread (offset 0), will sum 0, 8, 16, …
// ranging from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] We would like to use this // The second thread (offset 1), will sum 1, 9, 17, …
// set of numbers within 8 different threads simultaneously. Each thread is // The third thread (offset 2), will sum 2, 10, 18, …
// going to get the sum of every eighth value, with an offset. // …
// The eighth thread (offset 7), will sum 7, 15, 23, …
// //
// The first thread (offset 0), will sum 0, 8, 16, ... // Each thread should own a reference-counting pointer to the vector of
// The second thread (offset 1), will sum 1, 9, 17, ... // numbers. But `Rc` isn't thread-safe. Therefore, we need to use `Arc`.
// The third thread (offset 2), will sum 2, 10, 18, ...
// ...
// The eighth thread (offset 7), will sum 7, 15, 23, ...
// //
// Because we are using threads, our values need to be thread-safe. Therefore, // Don't get distracted by how threads are spawned and joined. We will practice
// we are using Arc. We need to make a change in each of the two TODOs. // that later in the exercises about threads.
//
// Make this code compile by filling in a value for `shared_numbers` where the
// first TODO comment is, and create an initial binding for `child_numbers`
// where the second TODO comment is. Try not to create any copies of the
// `numbers` Vec!
//
// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE // Don't change the lines below.
#![forbid(unused_imports)]
#![forbid(unused_imports)] // Do not change this, (or the next) line. use std::{sync::Arc, thread};
use std::sync::Arc;
use std::thread;
fn main() { fn main() {
let numbers: Vec<_> = (0..100u32).collect(); let numbers: Vec<_> = (0..100u32).collect();
let shared_numbers = // TODO
let mut joinhandles = Vec::new(); // TODO: Define `shared_numbers` by using `Arc`.
// let shared_numbers = ???;
let mut join_handles = Vec::new();
for offset in 0..8 { for offset in 0..8 {
let child_numbers = // TODO // TODO: Define `child_numbers` using `shared_numbers`.
joinhandles.push(thread::spawn(move || { // let child_numbers = ???;
let handle = thread::spawn(move || {
let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum(); let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum();
println!("Sum of offset {} is {}", offset, sum); println!("Sum of offset {offset} is {sum}");
})); });
join_handles.push(handle);
} }
for handle in joinhandles.into_iter() {
for handle in join_handles.into_iter() {
handle.join().unwrap(); handle.join().unwrap();
} }
} }

View file

@ -1,58 +1,50 @@
// box1.rs
//
// At compile time, Rust needs to know how much space a type takes up. This // At compile time, Rust needs to know how much space a type takes up. This
// becomes problematic for recursive types, where a value can have as part of // becomes problematic for recursive types, where a value can have as part of
// itself another value of the same type. To get around the issue, we can use a // itself another value of the same type. To get around the issue, we can use a
// `Box` - a smart pointer used to store data on the heap, which also allows us // `Box` - a smart pointer used to store data on the heap, which also allows us
// to wrap a recursive type. // to wrap a recursive type.
// //
// The recursive type we're implementing in this exercise is the `cons list` - a // The recursive type we're implementing in this exercise is the "cons list", a
// data structure frequently found in functional programming languages. Each // data structure frequently found in functional programming languages. Each
// item in a cons list contains two elements: the value of the current item and // item in a cons list contains two elements: The value of the current item and
// the next item. The last item is a value called `Nil`. // the next item. The last item is a value called `Nil`.
//
// Step 1: use a `Box` in the enum definition to make the code compile
// Step 2: create both empty and non-empty cons lists by replacing `todo!()`
//
// Note: the tests should not be changed
//
// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
// TODO: Use a `Box` in the enum definition to make the code compile.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum List { enum List {
Cons(i32, List), Cons(i32, List),
Nil, Nil,
} }
// TODO: Create an empty cons list.
fn create_empty_list() -> List {
todo!()
}
// TODO: Create a non-empty cons list.
fn create_non_empty_list() -> List {
todo!()
}
fn main() { fn main() {
println!("This is an empty cons list: {:?}", create_empty_list()); println!("This is an empty cons list: {:?}", create_empty_list());
println!( println!(
"This is a non-empty cons list: {:?}", "This is a non-empty cons list: {:?}",
create_non_empty_list() create_non_empty_list(),
); );
} }
pub fn create_empty_list() -> List {
todo!()
}
pub fn create_non_empty_list() -> List {
todo!()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_create_empty_list() { fn test_create_empty_list() {
assert_eq!(List::Nil, create_empty_list()) assert_eq!(create_empty_list(), List::Nil);
} }
#[test] #[test]
fn test_create_non_empty_list() { fn test_create_non_empty_list() {
assert_ne!(create_empty_list(), create_non_empty_list()) assert_ne!(create_empty_list(), create_non_empty_list());
} }
} }

View file

@ -1,30 +1,22 @@
// cow1.rs // This exercise explores the `Cow` (Clone-On-Write) smart pointer. It can
// // enclose and provide immutable access to borrowed data and clone the data
// This exercise explores the Cow, or Clone-On-Write type. Cow is a // lazily when mutation or ownership is required. The type is designed to work
// clone-on-write smart pointer. It can enclose and provide immutable access to // with general borrowed data via the `Borrow` trait.
// borrowed data, and clone the data lazily when mutation or ownership is
// required. The type is designed to work with general borrowed data via the
// Borrow trait.
//
// This exercise is meant to show you what to expect when passing data to Cow.
// Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the
// TODO markers.
//
// Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
use std::borrow::Cow; use std::borrow::Cow;
fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> { fn abs_all(input: &mut Cow<[i32]>) {
for i in 0..input.len() { for ind in 0..input.len() {
let v = input[i]; let value = input[ind];
if v < 0 { if value < 0 {
// Clones into a vector if not already owned. // Clones into a vector if not already owned.
input.to_mut()[i] = -v; input.to_mut()[ind] = -value;
} }
} }
input }
fn main() {
// You can optionally experiment here.
} }
#[cfg(test)] #[cfg(test)]
@ -32,47 +24,45 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn reference_mutation() -> Result<(), &'static str> { fn reference_mutation() {
// Clone occurs because `input` needs to be mutated. // Clone occurs because `input` needs to be mutated.
let slice = [-1, 0, 1]; let vec = vec![-1, 0, 1];
let mut input = Cow::from(&slice[..]); let mut input = Cow::from(&vec);
match abs_all(&mut input) { abs_all(&mut input);
Cow::Owned(_) => Ok(()), assert!(matches!(input, Cow::Owned(_)));
_ => Err("Expected owned value"),
}
} }
#[test] #[test]
fn reference_no_mutation() -> Result<(), &'static str> { fn reference_no_mutation() {
// No clone occurs because `input` doesn't need to be mutated. // No clone occurs because `input` doesn't need to be mutated.
let slice = [0, 1, 2]; let vec = vec![0, 1, 2];
let mut input = Cow::from(&slice[..]); let mut input = Cow::from(&vec);
match abs_all(&mut input) { abs_all(&mut input);
// TODO // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
} assert!(matches!(input, todo!()));
} }
#[test] #[test]
fn owned_no_mutation() -> Result<(), &'static str> { fn owned_no_mutation() {
// We can also pass `slice` without `&` so Cow owns it directly. In this // We can also pass `vec` without `&` so `Cow` owns it directly. In this
// case no mutation occurs and thus also no clone, but the result is // case, no mutation occurs and thus also no clone. But the result is
// still owned because it was never borrowed or mutated. // still owned because it was never borrowed or mutated.
let slice = vec![0, 1, 2]; let vec = vec![0, 1, 2];
let mut input = Cow::from(slice); let mut input = Cow::from(vec);
match abs_all(&mut input) { abs_all(&mut input);
// TODO // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
} assert!(matches!(input, todo!()));
} }
#[test] #[test]
fn owned_mutation() -> Result<(), &'static str> { fn owned_mutation() {
// Of course this is also the case if a mutation does occur. In this // Of course this is also the case if a mutation does occur. In this
// case the call to `to_mut()` in the abs_all() function returns a // case, the call to `to_mut()` in the `abs_all` function returns a
// reference to the same data as before. // reference to the same data as before.
let slice = vec![-1, 0, 1]; let vec = vec![-1, 0, 1];
let mut input = Cow::from(slice); let mut input = Cow::from(vec);
match abs_all(&mut input) { abs_all(&mut input);
// TODO // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`.
} assert!(matches!(input, todo!()));
} }
} }

View file

@ -1,22 +1,14 @@
// rc1.rs
//
// In this exercise, we want to express the concept of multiple owners via the // In this exercise, we want to express the concept of multiple owners via the
// Rc<T> type. This is a model of our solar system - there is a Sun type and // `Rc<T>` type. This is a model of our solar system - there is a `Sun` type and
// multiple Planets. The Planets take ownership of the sun, indicating that they // multiple `Planet`s. The planets take ownership of the sun, indicating that
// revolve around the sun. // they revolve around the sun.
//
// Make this code compile by using the proper Rc primitives to express that the
// sun has multiple owners.
//
// Execute `rustlings hint rc1` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
struct Sun {} struct Sun;
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
enum Planet { enum Planet {
Mercury(Rc<Sun>), Mercury(Rc<Sun>),
@ -31,75 +23,84 @@ enum Planet {
impl Planet { impl Planet {
fn details(&self) { fn details(&self) {
println!("Hi from {:?}!", self) println!("Hi from {self:?}!");
} }
} }
#[test]
fn main() { fn main() {
let sun = Rc::new(Sun {}); // You can optionally experiment here.
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference }
let mercury = Planet::Mercury(Rc::clone(&sun)); #[cfg(test)]
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references mod tests {
mercury.details(); use super::*;
let venus = Planet::Venus(Rc::clone(&sun)); #[test]
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references fn rc1() {
venus.details(); let sun = Rc::new(Sun);
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
let earth = Planet::Earth(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references let mercury = Planet::Mercury(Rc::clone(&sun));
earth.details(); println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
mercury.details();
let mars = Planet::Mars(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references let venus = Planet::Venus(Rc::clone(&sun));
mars.details(); println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
venus.details();
let jupiter = Planet::Jupiter(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references let earth = Planet::Earth(Rc::clone(&sun));
jupiter.details(); println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
earth.details();
// TODO
let saturn = Planet::Saturn(Rc::new(Sun {})); let mars = Planet::Mars(Rc::clone(&sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
saturn.details(); mars.details();
// TODO let jupiter = Planet::Jupiter(Rc::clone(&sun));
let uranus = Planet::Uranus(Rc::new(Sun {})); println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references jupiter.details();
uranus.details();
// TODO
// TODO let saturn = Planet::Saturn(Rc::new(Sun));
let neptune = Planet::Neptune(Rc::new(Sun {})); println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references saturn.details();
neptune.details();
// TODO
assert_eq!(Rc::strong_count(&sun), 9); let uranus = Planet::Uranus(Rc::new(Sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
drop(neptune); uranus.details();
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
// TODO
drop(uranus); let neptune = Planet::Neptune(Rc::new(Sun));
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
neptune.details();
drop(saturn);
println!("reference count = {}", Rc::strong_count(&sun)); // 6 references assert_eq!(Rc::strong_count(&sun), 9);
drop(jupiter); drop(neptune);
println!("reference count = {}", Rc::strong_count(&sun)); // 5 references println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
drop(mars); drop(uranus);
println!("reference count = {}", Rc::strong_count(&sun)); // 4 references println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
// TODO drop(saturn);
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references println!("reference count = {}", Rc::strong_count(&sun)); // 6 references
// TODO drop(jupiter);
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references println!("reference count = {}", Rc::strong_count(&sun)); // 5 references
// TODO drop(mars);
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference println!("reference count = {}", Rc::strong_count(&sun)); // 4 references
assert_eq!(Rc::strong_count(&sun), 1); // TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 3 references
// TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 2 references
// TODO
println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference
assert_eq!(Rc::strong_count(&sun), 1);
}
} }

View file

@ -7,3 +7,4 @@ Within your program, you can also have independent parts that run simultaneously
- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) - [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) - [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
- [Using Message Passing to Transfer Data Between Threads](https://doc.rust-lang.org/book/ch16-02-message-passing.html)

View file

@ -1,40 +1,37 @@
// threads1.rs
//
// This program spawns multiple threads that each run for at least 250ms, and // This program spawns multiple threads that each run for at least 250ms, and
// each thread returns how much time they took to complete. The program should // each thread returns how much time they took to complete. The program should
// wait until all the spawned threads have finished and should collect their // wait until all the spawned threads have finished and should collect their
// return values into a vector. // return values into a vector.
//
// Execute `rustlings hint threads1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE use std::{
thread,
use std::thread; time::{Duration, Instant},
use std::time::{Duration, Instant}; };
fn main() { fn main() {
let mut handles = vec![]; let mut handles = Vec::new();
for i in 0..10 { for i in 0..10 {
handles.push(thread::spawn(move || { let handle = thread::spawn(move || {
let start = Instant::now(); let start = Instant::now();
thread::sleep(Duration::from_millis(250)); thread::sleep(Duration::from_millis(250));
println!("thread {} is complete", i); println!("Thread {i} done");
start.elapsed().as_millis() start.elapsed().as_millis()
})); });
handles.push(handle);
} }
let mut results: Vec<u128> = vec![]; let mut results = Vec::new();
for handle in handles { for handle in handles {
// TODO: a struct is returned from thread::spawn, can you use it? // TODO: Collect the results of all threads into the `results` vector.
// Use the `JoinHandle` struct which is returned by `thread::spawn`.
} }
if results.len() != 10 { if results.len() != 10 {
panic!("Oh no! All the spawned threads did not finish!"); panic!("Oh no! Some thread isn't done yet!");
} }
println!(); println!();
for (i, result) in results.into_iter().enumerate() { for (i, result) in results.into_iter().enumerate() {
println!("thread {} took {}ms", i, result); println!("Thread {i} took {result}ms");
} }
} }

Some files were not shown because too many files have changed in this diff Show more