Merge branch '5.0-dev'
This commit is contained in:
commit
c791cf4232
|
@ -0,0 +1,20 @@
|
||||||
|
name: Rustlings Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
|
@ -9,3 +9,4 @@ rust-project.json
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
*.iml
|
*.iml
|
||||||
|
*.o
|
||||||
|
|
|
@ -21,7 +21,7 @@ _implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull
|
||||||
|
|
||||||
`rustlings` is basically a glorified `rustc` wrapper. Therefore 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`.
|
isn't really that complicated since the bulk of the work is done by `rustc`.
|
||||||
`src/main.rs` contains a simple `clap` CLI that loads from `src/verify.rs` and `src/run.rs`.
|
`src/main.rs` contains a simple `argh` CLI that connects to most of the other source files.
|
||||||
|
|
||||||
<a name="addex"></a>
|
<a name="addex"></a>
|
||||||
### Adding an exercise
|
### Adding an exercise
|
||||||
|
@ -29,7 +29,7 @@ isn't really that complicated since the bulk of the work is done by `rustc`.
|
||||||
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
|
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`.
|
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`.
|
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:
|
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
|
```diff
|
||||||
|
@ -43,7 +43,7 @@ Add the metadata for your exercise in the correct order in the `exercises` array
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
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`.
|
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.
|
That's all! Feel free to put up a pull request.
|
||||||
|
|
||||||
|
@ -67,19 +67,19 @@ changes. There's a couple of things to watch out for:
|
||||||
#### Write correct commit messages
|
#### Write correct commit messages
|
||||||
|
|
||||||
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
|
We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/)
|
||||||
specification, because it makes it easier to generate changelogs automatically.
|
specification.
|
||||||
This means that you have to format your commit messages in a specific way. Say
|
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
|
you're working on adding a new exercise called `foobar1.rs`. You could write
|
||||||
the following commit message:
|
the following commit message:
|
||||||
|
|
||||||
```
|
```
|
||||||
feat: Add foobar1.rs exercise
|
feat: add foobar1.rs exercise
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're just fixing a bug, please use the `fix` type:
|
If you're just fixing a bug, please use the `fix` type:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix(verify): Make sure verify doesn't self-destruct
|
fix(verify): make sure verify doesn't self-destruct
|
||||||
```
|
```
|
||||||
|
|
||||||
The scope within the brackets is optional, but should be any of these:
|
The scope within the brackets is optional, but should be any of these:
|
||||||
|
@ -96,7 +96,7 @@ When the commit also happens to close an existing issue, link it in the message
|
||||||
body:
|
body:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix: Update foobar
|
fix: update foobar
|
||||||
|
|
||||||
closes #101029908
|
closes #101029908
|
||||||
```
|
```
|
||||||
|
@ -104,13 +104,13 @@ closes #101029908
|
||||||
If you're doing simple changes, like updating a book link, use `chore`:
|
If you're doing simple changes, like updating a book link, use `chore`:
|
||||||
|
|
||||||
```
|
```
|
||||||
chore: Update exercise1.rs book link
|
chore: update exercise1.rs book link
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're updating documentation, use `docs`:
|
If you're updating documentation, use `docs`:
|
||||||
|
|
||||||
```
|
```
|
||||||
docs: Add more information to Readme
|
docs: add more information to Readme
|
||||||
```
|
```
|
||||||
|
|
||||||
If, and only if, you're absolutely sure you want to make a breaking change
|
If, and only if, you're absolutely sure you want to make a breaking change
|
||||||
|
@ -118,7 +118,7 @@ If, and only if, you're absolutely sure you want to make a breaking change
|
||||||
explain the breaking change in the message body:
|
explain the breaking change in the message body:
|
||||||
|
|
||||||
```
|
```
|
||||||
fix!: Completely change verification
|
fix!: completely change verification
|
||||||
|
|
||||||
BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
||||||
```
|
```
|
||||||
|
@ -126,6 +126,5 @@ BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
||||||
#### Pull Request Workflow
|
#### Pull Request Workflow
|
||||||
|
|
||||||
Once you open a Pull Request, it may be reviewed or labeled (or both) until
|
Once you open a Pull Request, it may be reviewed or labeled (or both) until
|
||||||
the maintainers accept your change. Then, [bors](https://github.com/bors) will
|
the maintainers accept your change. Please be patient, it may take some time
|
||||||
run the test suite with your changes and if it's successful, automatically
|
for this to happen!
|
||||||
merge it in!
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "4.7.1"
|
version = "4.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
version = "4.8.0"
|
version = "4.8.0"
|
||||||
authors = ["mokou <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
authors = ["Liv <mokou@fastmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -24,6 +24,3 @@ path = "src/main.rs"
|
||||||
assert_cmd = "0.11.0"
|
assert_cmd = "0.11.0"
|
||||||
predicates = "1.0.1"
|
predicates = "1.0.1"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
exercises = []
|
|
||||||
|
|
22
README.md
22
README.md
|
@ -44,9 +44,9 @@ Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings
|
||||||
|
|
||||||
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
|
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
|
||||||
|
|
||||||
When you get a permission denied message then you have to exclude the directory where you placed the rustlings in your virus-scanner
|
If you get a permission denied message, you might have to exclude the directory where you cloned Rustlings in your antivirus.
|
||||||
|
|
||||||
## Browser:
|
## Browser
|
||||||
|
|
||||||
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
|
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
|
||||||
|
|
||||||
|
@ -150,24 +150,6 @@ cargo uninstall rustlings
|
||||||
|
|
||||||
Now you should be done!
|
Now you should be done!
|
||||||
|
|
||||||
## Completion
|
|
||||||
|
|
||||||
Rustlings isn't done; there are a couple of sections that are very experimental and don't have proper documentation. These include:
|
|
||||||
|
|
||||||
- Errors (`exercises/errors/`)
|
|
||||||
- Option (`exercises/option/`)
|
|
||||||
- Result (`exercises/result/`)
|
|
||||||
- Move Semantics (could still be improved, `exercises/move_semantics/`)
|
|
||||||
|
|
||||||
Additionally, we could use exercises on a couple of topics:
|
|
||||||
|
|
||||||
- Structs
|
|
||||||
- Better ownership stuff
|
|
||||||
- `impl`
|
|
||||||
- ??? probably more
|
|
||||||
|
|
||||||
If you are interested in improving or adding new ones, please feel free to contribute! Read on for more information :)
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
// advanced_errs1.rs
|
|
||||||
|
|
||||||
// Remember back in errors6, we had multiple mapping functions so that we
|
|
||||||
// could translate lower-level errors into our custom error type using
|
|
||||||
// `map_err()`? What if we could use the `?` operator directly instead?
|
|
||||||
|
|
||||||
// Make this code compile! Execute `rustlings hint advanced_errs1` for
|
|
||||||
// hints :)
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
// This is a custom error type that we will be using in the `FromStr`
|
|
||||||
// implementation.
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum ParsePosNonzeroError {
|
|
||||||
Creation(CreationError),
|
|
||||||
ParseInt(ParseIntError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CreationError> for ParsePosNonzeroError {
|
|
||||||
fn from(e: CreationError) -> Self {
|
|
||||||
// TODO: complete this implementation so that the `?` operator will
|
|
||||||
// work for `CreationError`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement another instance of the `From` trait here so that the
|
|
||||||
// `?` operator will work in the other place in the `FromStr`
|
|
||||||
// implementation below.
|
|
||||||
|
|
||||||
// Don't change anything below this line.
|
|
||||||
|
|
||||||
impl FromStr for PositiveNonzeroInteger {
|
|
||||||
type Err = ParsePosNonzeroError;
|
|
||||||
fn from_str(s: &str) -> Result<PositiveNonzeroInteger, Self::Err> {
|
|
||||||
let x: i64 = s.parse()?;
|
|
||||||
Ok(PositiveNonzeroInteger::new(x)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
struct PositiveNonzeroInteger(u64);
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
enum CreationError {
|
|
||||||
Negative,
|
|
||||||
Zero,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
|
||||||
match value {
|
|
||||||
x if x < 0 => Err(CreationError::Negative),
|
|
||||||
x if x == 0 => Err(CreationError::Zero),
|
|
||||||
x => Ok(PositiveNonzeroInteger(x as u64)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_error() {
|
|
||||||
// We can't construct a ParseIntError, so we have to pattern match.
|
|
||||||
assert!(matches!(
|
|
||||||
PositiveNonzeroInteger::from_str("not a number"),
|
|
||||||
Err(ParsePosNonzeroError::ParseInt(_))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_negative() {
|
|
||||||
assert_eq!(
|
|
||||||
PositiveNonzeroInteger::from_str("-555"),
|
|
||||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero() {
|
|
||||||
assert_eq!(
|
|
||||||
PositiveNonzeroInteger::from_str("0"),
|
|
||||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_positive() {
|
|
||||||
let x = PositiveNonzeroInteger::new(42);
|
|
||||||
assert!(x.is_ok());
|
|
||||||
assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,202 +0,0 @@
|
||||||
// advanced_errs2.rs
|
|
||||||
|
|
||||||
// This exercise demonstrates a few traits that are useful for custom error
|
|
||||||
// types to implement, especially so that other code can consume the custom
|
|
||||||
// error type more usefully.
|
|
||||||
|
|
||||||
// Make this compile, and make the tests pass!
|
|
||||||
// Execute `rustlings hint advanced_errs2` for hints.
|
|
||||||
|
|
||||||
// Steps:
|
|
||||||
// 1. Implement a missing trait so that `main()` will compile.
|
|
||||||
// 2. Complete the partial implementation of `From` for
|
|
||||||
// `ParseClimateError`.
|
|
||||||
// 3. Handle the missing error cases in the `FromStr` implementation for
|
|
||||||
// `Climate`.
|
|
||||||
// 4. Complete the partial implementation of `Display` for
|
|
||||||
// `ParseClimateError`.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
use std::num::{ParseFloatError, ParseIntError};
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
// This is the custom error type that we will be using for the parser for
|
|
||||||
// `Climate`.
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum ParseClimateError {
|
|
||||||
Empty,
|
|
||||||
BadLen,
|
|
||||||
NoCity,
|
|
||||||
ParseInt(ParseIntError),
|
|
||||||
ParseFloat(ParseFloatError),
|
|
||||||
}
|
|
||||||
|
|
||||||
// This `From` implementation allows the `?` operator to work on
|
|
||||||
// `ParseIntError` values.
|
|
||||||
impl From<ParseIntError> for ParseClimateError {
|
|
||||||
fn from(e: ParseIntError) -> Self {
|
|
||||||
Self::ParseInt(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This `From` implementation allows the `?` operator to work on
|
|
||||||
// `ParseFloatError` values.
|
|
||||||
impl From<ParseFloatError> for ParseClimateError {
|
|
||||||
fn from(e: ParseFloatError) -> Self {
|
|
||||||
// TODO: Complete this function
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement a missing trait so that `main()` below will compile. It
|
|
||||||
// is not necessary to implement any methods inside the missing trait.
|
|
||||||
|
|
||||||
// The `Display` trait allows for other code to obtain the error formatted
|
|
||||||
// as a user-visible string.
|
|
||||||
impl Display for ParseClimateError {
|
|
||||||
// TODO: Complete this function so that it produces the correct strings
|
|
||||||
// for each error variant.
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
// Imports the variants to make the following code more compact.
|
|
||||||
use ParseClimateError::*;
|
|
||||||
match self {
|
|
||||||
NoCity => write!(f, "no city name"),
|
|
||||||
ParseFloat(e) => write!(f, "error parsing temperature: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
struct Climate {
|
|
||||||
city: String,
|
|
||||||
year: u32,
|
|
||||||
temp: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parser for `Climate`.
|
|
||||||
// 1. Split the input string into 3 fields: city, year, temp.
|
|
||||||
// 2. Return an error if the string is empty or has the wrong number of
|
|
||||||
// fields.
|
|
||||||
// 3. Return an error if the city name is empty.
|
|
||||||
// 4. Parse the year as a `u32` and return an error if that fails.
|
|
||||||
// 5. Parse the temp as a `f32` and return an error if that fails.
|
|
||||||
// 6. Return an `Ok` value containing the completed `Climate` value.
|
|
||||||
impl FromStr for Climate {
|
|
||||||
type Err = ParseClimateError;
|
|
||||||
// TODO: Complete this function by making it handle the missing error
|
|
||||||
// cases.
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let v: Vec<_> = s.split(',').collect();
|
|
||||||
let (city, year, temp) = match &v[..] {
|
|
||||||
[city, year, temp] => (city.to_string(), year, temp),
|
|
||||||
_ => return Err(ParseClimateError::BadLen),
|
|
||||||
};
|
|
||||||
let year: u32 = year.parse()?;
|
|
||||||
let temp: f32 = temp.parse()?;
|
|
||||||
Ok(Climate { city, year, temp })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't change anything below this line (other than to enable ignored
|
|
||||||
// tests).
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
println!("{:?}", "Hong Kong,1999,25.7".parse::<Climate>()?);
|
|
||||||
println!("{:?}", "".parse::<Climate>()?);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_empty() {
|
|
||||||
let res = "".parse::<Climate>();
|
|
||||||
assert_eq!(res, Err(ParseClimateError::Empty));
|
|
||||||
assert_eq!(res.unwrap_err().to_string(), "empty input");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_short() {
|
|
||||||
let res = "Boston,1991".parse::<Climate>();
|
|
||||||
assert_eq!(res, Err(ParseClimateError::BadLen));
|
|
||||||
assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_long() {
|
|
||||||
let res = "Paris,1920,17.2,extra".parse::<Climate>();
|
|
||||||
assert_eq!(res, Err(ParseClimateError::BadLen));
|
|
||||||
assert_eq!(res.unwrap_err().to_string(), "incorrect number of fields");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_no_city() {
|
|
||||||
let res = ",1997,20.5".parse::<Climate>();
|
|
||||||
assert_eq!(res, Err(ParseClimateError::NoCity));
|
|
||||||
assert_eq!(res.unwrap_err().to_string(), "no city name");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_parse_int_neg() {
|
|
||||||
let res = "Barcelona,-25,22.3".parse::<Climate>();
|
|
||||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
|
||||||
let err = res.unwrap_err();
|
|
||||||
if let ParseClimateError::ParseInt(ref inner) = err {
|
|
||||||
assert_eq!(
|
|
||||||
err.to_string(),
|
|
||||||
format!("error parsing year: {}", inner.to_string())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_parse_int_bad() {
|
|
||||||
let res = "Beijing,foo,15.0".parse::<Climate>();
|
|
||||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
|
||||||
let err = res.unwrap_err();
|
|
||||||
if let ParseClimateError::ParseInt(ref inner) = err {
|
|
||||||
assert_eq!(
|
|
||||||
err.to_string(),
|
|
||||||
format!("error parsing year: {}", inner.to_string())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_parse_float() {
|
|
||||||
let res = "Manila,2001,bar".parse::<Climate>();
|
|
||||||
assert!(matches!(res, Err(ParseClimateError::ParseFloat(_))));
|
|
||||||
let err = res.unwrap_err();
|
|
||||||
if let ParseClimateError::ParseFloat(ref inner) = err {
|
|
||||||
assert_eq!(
|
|
||||||
err.to_string(),
|
|
||||||
format!("error parsing temperature: {}", inner.to_string())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_parse_good() {
|
|
||||||
let res = "Munich,2015,23.1".parse::<Climate>();
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
Ok(Climate {
|
|
||||||
city: "Munich".to_string(),
|
|
||||||
year: 2015,
|
|
||||||
temp: 23.1,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn test_downcast() {
|
|
||||||
let res = "São Paulo,-21,28.5".parse::<Climate>();
|
|
||||||
assert!(matches!(res, Err(ParseClimateError::ParseInt(_))));
|
|
||||||
let err = res.unwrap_err();
|
|
||||||
let inner: Option<&(dyn Error + 'static)> = err.source();
|
|
||||||
assert!(inner.is_some());
|
|
||||||
assert!(inner.unwrap().is::<ParseIntError>());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
mod advanced_errs1;
|
|
||||||
mod advanced_errs2;
|
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// For these exercises the code will fail to compile when there are clippy warnings
|
// For these exercises the code will fail to compile when there are clippy warnings
|
||||||
// check clippy's suggestions from the output to solve the exercise.
|
// check clippy's suggestions from the output to solve the exercise.
|
||||||
// Execute `rustlings hint clippy1` for hints :)
|
// Execute `rustlings hint clippy1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// clippy2.rs
|
// clippy2.rs
|
||||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
// Execute `rustlings hint clippy2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// clippy3.rs
|
||||||
|
// Here's a couple more easy Clippy fixes, so you can see its utility.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
#[allow(unused_variables, unused_assignments)]
|
||||||
|
fn main() {
|
||||||
|
let my_option: Option<()> = None;
|
||||||
|
if my_option.is_none() {
|
||||||
|
my_option.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let my_arr = &[
|
||||||
|
-1, -2, -3
|
||||||
|
-4, -5, -6
|
||||||
|
];
|
||||||
|
println!("My array! Here it is: {:?}", my_arr);
|
||||||
|
|
||||||
|
let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5);
|
||||||
|
println!("This Vec is empty, see? {:?}", my_empty_vec);
|
||||||
|
|
||||||
|
let mut value_a = 45;
|
||||||
|
let mut value_b = 66;
|
||||||
|
// Let's swap these two!
|
||||||
|
value_a = value_b;
|
||||||
|
value_b = value_a;
|
||||||
|
println!("value a: {}; value b: {}", value_a, value_b);
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
mod clippy1;
|
|
||||||
mod clippy2;
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Collections
|
|
||||||
|
|
||||||
Rust’s standard library includes a number of very useful data
|
|
||||||
structures called collections. Most other data types represent one
|
|
||||||
specific value, but collections can contain multiple values. Unlike
|
|
||||||
the built-in array and tuple types, the data these collections point
|
|
||||||
to is stored on the heap, which means the amount of data does not need
|
|
||||||
to be known at compile time and can grow or shrink as the program
|
|
||||||
runs.
|
|
||||||
|
|
||||||
This exercise will get you familiar with two fundamental data
|
|
||||||
structures that are used very often in Rust programs:
|
|
||||||
|
|
||||||
* A *vector* allows you to store a variable number of values next to
|
|
||||||
each other.
|
|
||||||
* A *hash map* allows you to associate a value with a particular key.
|
|
||||||
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
|
|
||||||
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
|
|
||||||
|
|
||||||
## Further information
|
|
||||||
|
|
||||||
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
|
|
||||||
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
|
|
@ -1,4 +0,0 @@
|
||||||
mod hashmap1;
|
|
||||||
mod hashmap2;
|
|
||||||
mod vec1;
|
|
||||||
mod vec2;
|
|
|
@ -1,6 +1,7 @@
|
||||||
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
||||||
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
||||||
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
||||||
|
// Execute `rustlings hint as_ref_mut` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -16,10 +17,10 @@ fn char_counter<T>(arg: T) -> usize {
|
||||||
arg.as_ref().chars().count()
|
arg.as_ref().chars().count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
// Squares a number using AsMut. Add the trait bound as is appropriate and
|
||||||
let s = "Café au lait";
|
// implement the function body.
|
||||||
println!("{}", char_counter(s));
|
fn num_sq<T>(arg: &mut T) {
|
||||||
println!("{}", byte_counter(s));
|
???
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -49,4 +50,11 @@ mod tests {
|
||||||
let s = String::from("Cafe au lait");
|
let s = String::from("Cafe au lait");
|
||||||
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mult_box() {
|
||||||
|
let mut num: Box<u32> = Box::new(3);
|
||||||
|
num_sq(&mut num);
|
||||||
|
assert_eq!(*num, 9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// The From trait is used for value-to-value conversions.
|
// The From trait is used for value-to-value conversions.
|
||||||
// If From is implemented correctly for a type, the Into trait should work conversely.
|
// If From is implemented correctly for a type, the Into trait should work conversely.
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
||||||
|
// Execute `rustlings hint from_into` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Person {
|
struct Person {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
// Additionally, upon implementing FromStr, you can use the `parse` method
|
// Additionally, upon implementing FromStr, you can use the `parse` method
|
||||||
// on strings to generate an object of the implementor type.
|
// on strings to generate an object of the implementor type.
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
||||||
|
// Execute `rustlings hint from_str` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -37,6 +39,9 @@ enum ParsePersonError {
|
||||||
// with something like `"4".parse::<usize>()`
|
// with something like `"4".parse::<usize>()`
|
||||||
// 6. If while extracting the name and the age something goes wrong, an error should be returned
|
// 6. If while extracting the name and the age something goes wrong, an error should be returned
|
||||||
// If everything goes well, then return a Result of a Person object
|
// If everything goes well, then return a Result of a Person object
|
||||||
|
//
|
||||||
|
// As an aside: `Box<dyn Error>` implements `From<&'_ str>`. This means that if you want to return a
|
||||||
|
// string error message, you can do so via just using return `Err("my error message".into())`.
|
||||||
|
|
||||||
impl FromStr for Person {
|
impl FromStr for Person {
|
||||||
type Err = ParsePersonError;
|
type Err = ParsePersonError;
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
mod as_ref_mut;
|
|
||||||
mod from_into;
|
|
||||||
mod from_str;
|
|
||||||
mod try_from_into;
|
|
||||||
mod using_as;
|
|
|
@ -3,6 +3,8 @@
|
||||||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
// Basically, this is the same as From. The main difference is that this should return a Result type
|
||||||
// instead of the target type itself.
|
// instead of the target type itself.
|
||||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||||
|
// Execute `rustlings hint try_from_into` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -54,7 +56,7 @@ impl TryFrom<&[i16]> for Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Use the `from` function
|
// Use the `try_from` function
|
||||||
let c1 = Color::try_from((183, 65, 14));
|
let c1 = Color::try_from((183, 65, 14));
|
||||||
println!("{:?}", c1);
|
println!("{:?}", c1);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//
|
//
|
||||||
// The goal is to make sure that the division does not fail to compile
|
// The goal is to make sure that the division does not fail to compile
|
||||||
// and returns the proper type.
|
// and returns the proper type.
|
||||||
|
// Execute `rustlings hint using_as` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// enums1.rs
|
// enums1.rs
|
||||||
// Make me compile! Execute `rustlings hint enums1` for hints!
|
// No hints this time! ;)
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// enums2.rs
|
// enums2.rs
|
||||||
// Make me compile! Execute `rustlings hint enums2` for hints!
|
// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// enums3.rs
|
// enums3.rs
|
||||||
// Address all the TODOs to make the tests pass!
|
// 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
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod enums1;
|
|
||||||
mod enums2;
|
|
||||||
mod enums3;
|
|
|
@ -3,16 +3,16 @@
|
||||||
// you pass it an empty string. It'd be nicer if it explained what the problem
|
// you pass it an empty string. It'd be nicer if it explained what the problem
|
||||||
// was, instead of just sometimes returning `None`. Thankfully, Rust has a similar
|
// was, instead of just sometimes returning `None`. Thankfully, Rust has a similar
|
||||||
// construct to `Option` that can be used to express error conditions. Let's use it!
|
// construct to `Option` that can be used to express error conditions. Let's use it!
|
||||||
// Execute `rustlings hint errors1` for hints!
|
// Execute `rustlings hint errors1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
pub fn generate_nametag_text(name: String) -> Option<String> {
|
pub fn generate_nametag_text(name: String) -> Option<String> {
|
||||||
if name.len() > 0 {
|
if name.is_empty() {
|
||||||
Some(format!("Hi! My name is {}", name))
|
|
||||||
} else {
|
|
||||||
// Empty names aren't allowed.
|
// Empty names aren't allowed.
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(format!("Hi! My name is {}", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
// and add.
|
// and add.
|
||||||
|
|
||||||
// There are at least two ways to implement this that are both correct-- but
|
// There are at least two ways to implement this that are both correct-- but
|
||||||
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
|
// one is a lot shorter!
|
||||||
|
// Execute `rustlings hint errors2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// 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` for hints!
|
// Execute `rustlings hint errors3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// errors4.rs
|
// errors4.rs
|
||||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
// Execute `rustlings hint errors4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ enum CreationError {
|
||||||
|
|
||||||
impl PositiveNonzeroInteger {
|
impl PositiveNonzeroInteger {
|
||||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||||
|
// Hmm...? Why is this only returning an Ok value?
|
||||||
Ok(PositiveNonzeroInteger(value as u64))
|
Ok(PositiveNonzeroInteger(value as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
// errors5.rs
|
// errors5.rs
|
||||||
|
|
||||||
// This program uses a completed version of the code from errors4.
|
// This program uses an altered version of the code from errors4.
|
||||||
// It won't compile right now! Why?
|
|
||||||
// Execute `rustlings hint errors5` for hints!
|
// This exercise uses some concepts that we won't get to until later in the course, like `Box` and the
|
||||||
|
// `From` trait. It's not important to understand them in detail right now, but you can read ahead if you like.
|
||||||
|
|
||||||
|
// 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 trait. To do so, The Box is declared as of type Box<dyn Trait> where Trait is the trait
|
||||||
|
// the compiler looks for on any value used in that context. For this exercise, that context is the potential errors
|
||||||
|
// which 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
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -11,7 +21,7 @@ use std::fmt;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
// TODO: update the return type of `main()` to make this compile.
|
// TODO: update the return type of `main()` to make this compile.
|
||||||
fn main() -> Result<(), ParseIntError> {
|
fn main() -> Result<(), Box<dyn ???>> {
|
||||||
let pretend_user_input = "42";
|
let pretend_user_input = "42";
|
||||||
let x: i64 = pretend_user_input.parse()?;
|
let x: i64 = pretend_user_input.parse()?;
|
||||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// we define a custom error type to make it possible for callers to decide
|
// we define a custom error type to make it possible for callers to decide
|
||||||
// what to do next when our function returns an error.
|
// what to do next when our function returns an error.
|
||||||
|
|
||||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
// Execute `rustlings hint errors6` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -20,7 +20,11 @@ enum ParsePosNonzeroError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsePosNonzeroError {
|
impl ParsePosNonzeroError {
|
||||||
|
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
||||||
|
ParsePosNonzeroError::Creation(err)
|
||||||
|
}
|
||||||
// TODO: add another error conversion function here.
|
// TODO: add another error conversion function here.
|
||||||
|
// fn from_parseint...
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pos_nonzero(s: &str)
|
fn parse_pos_nonzero(s: &str)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
mod errors1;
|
|
||||||
mod errors2;
|
|
||||||
mod errors3;
|
|
||||||
mod errors4;
|
|
||||||
mod errors5;
|
|
||||||
mod errors6;
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Functions
|
# Functions
|
||||||
|
|
||||||
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
|
Here, you'll learn how to write functions and how the Rust compiler can help you debug errors even
|
||||||
|
in more complex code.
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// functions1.rs
|
// functions1.rs
|
||||||
// Make me compile! Execute `rustlings hint functions1` for hints :)
|
// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// functions2.rs
|
// functions2.rs
|
||||||
// Make me compile! Execute `rustlings hint functions2` for hints :)
|
// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// functions3.rs
|
// functions3.rs
|
||||||
// Make me compile! Execute `rustlings hint functions3` for hints :)
|
// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
// functions4.rs
|
// functions4.rs
|
||||||
// Make me compile! Execute `rustlings hint functions4` for hints :)
|
// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// This store is having a sale where if the price is an even number, you get
|
// 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.
|
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
|
||||||
|
// (Don't worry about the function bodies themselves, we're only interested
|
||||||
|
// in the signatures for now. If anything, this is a good way to peek ahead
|
||||||
|
// to future exercises!)
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// functions5.rs
|
// functions5.rs
|
||||||
// Make me compile! Execute `rustlings hint functions5` for hints :)
|
// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let answer = square(3);
|
let answer = square(3);
|
||||||
println!("The answer is {}", answer);
|
println!("The square of 3 is {}", answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn square(num: i32) -> i32 {
|
fn square(num: i32) -> i32 {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
mod functions1;
|
|
||||||
mod functions2;
|
|
||||||
mod functions3;
|
|
||||||
mod functions4;
|
|
||||||
mod functions5;
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This shopping list program isn't compiling!
|
// This shopping list program isn't compiling!
|
||||||
// Use your knowledge of generics to fix it.
|
// Use your knowledge of generics to fix it.
|
||||||
|
|
||||||
// Execute `rustlings hint generics1` for hints!
|
// Execute `rustlings hint generics1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// 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.
|
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||||
|
|
||||||
// Execute `rustlings hint generics2` for hints!
|
// Execute `rustlings hint generics2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
// An imaginary magical school has a new report card generation system written in Rust!
|
|
||||||
// Currently the system only supports creating report cards where the student's grade
|
|
||||||
// is represented numerically (e.g. 1.0 -> 5.5).
|
|
||||||
// However, the school also issues alphabetical grades (A+ -> F-) and needs
|
|
||||||
// to be able to print both types of report card!
|
|
||||||
|
|
||||||
// Make the necessary code changes in the struct ReportCard and the impl block
|
|
||||||
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
|
||||||
// to show that your changes allow alphabetical grades.
|
|
||||||
|
|
||||||
// Execute 'rustlings hint generics3' for hints!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
pub struct ReportCard {
|
|
||||||
pub grade: f32,
|
|
||||||
pub student_name: String,
|
|
||||||
pub student_age: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReportCard {
|
|
||||||
pub fn print(&self) -> String {
|
|
||||||
format!("{} ({}) - achieved a grade of {}",
|
|
||||||
&self.student_name, &self.student_age, &self.grade)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generate_numeric_report_card() {
|
|
||||||
let report_card = ReportCard {
|
|
||||||
grade: 2.1,
|
|
||||||
student_name: "Tom Wriggle".to_string(),
|
|
||||||
student_age: 12,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
report_card.print(),
|
|
||||||
"Tom Wriggle (12) - achieved a grade of 2.1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generate_alphabetic_report_card() {
|
|
||||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
|
||||||
let report_card = ReportCard {
|
|
||||||
grade: 2.1,
|
|
||||||
student_name: "Gary Plotter".to_string(),
|
|
||||||
student_age: 11,
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
report_card.print(),
|
|
||||||
"Gary Plotter (11) - achieved a grade of A+"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod generics1;
|
|
||||||
mod generics2;
|
|
||||||
mod generics3;
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Hashmaps
|
||||||
|
A *hash map* allows you to associate a value with a particular key.
|
||||||
|
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
|
||||||
|
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
|
||||||
|
|
||||||
|
This is the other data structure that we've been talking about before, when
|
||||||
|
talking about Vecs.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
|
@ -1,4 +1,4 @@
|
||||||
// hashmap1.rs
|
// hashmaps1.rs
|
||||||
// A basket of fruits in the form of a hash map needs to be defined.
|
// 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
|
// The key represents the name of the fruit and the value represents
|
||||||
// how many of that particular fruit is in the basket. You have to put
|
// how many of that particular fruit is in the basket. You have to put
|
||||||
|
@ -8,8 +8,7 @@
|
||||||
//
|
//
|
||||||
// Make me compile and pass the tests!
|
// Make me compile and pass the tests!
|
||||||
//
|
//
|
||||||
// Execute the command `rustlings hint hashmap1` if you need
|
// Execute `rustlings hint hashmaps1` or use the `hint` watch subcommand for a hint.
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// hashmap2.rs
|
// hashmaps2.rs
|
||||||
|
|
||||||
// A basket of fruits in the form of a hash map is given. The key
|
// A basket of fruits in the form of a hash map is given. The key
|
||||||
// represents the name of the fruit and the value represents how many
|
// represents the name of the fruit and the value represents how many
|
||||||
|
@ -9,8 +9,7 @@
|
||||||
//
|
//
|
||||||
// Make me pass the tests!
|
// Make me pass the tests!
|
||||||
//
|
//
|
||||||
// Execute the command `rustlings hint hashmap2` if you need
|
// Execute `rustlings hint hashmaps2` or use the `hint` watch subcommand for a hint.
|
||||||
// hints.
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
// hashmaps3.rs
|
||||||
|
|
||||||
|
// 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>
|
||||||
|
// 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 team scored, and goals the team conceded. One approach to build
|
||||||
|
// the scores table is to use a Hashmap. The solution is partially
|
||||||
|
// written to use a 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;
|
||||||
|
|
||||||
|
// A structure to store team name and its goal details.
|
||||||
|
struct Team {
|
||||||
|
name: String,
|
||||||
|
goals_scored: u8,
|
||||||
|
goals_conceded: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_scores_table(results: String) -> HashMap<String, Team> {
|
||||||
|
// The name of the team is the key and its associated struct is the value.
|
||||||
|
let mut scores: HashMap<String, Team> = HashMap::new();
|
||||||
|
|
||||||
|
for r in results.lines() {
|
||||||
|
let v: Vec<&str> = r.split(',').collect();
|
||||||
|
let team_1_name = v[0].to_string();
|
||||||
|
let team_1_score: u8 = v[2].parse().unwrap();
|
||||||
|
let team_2_name = v[1].to_string();
|
||||||
|
let team_2_score: u8 = v[3].parse().unwrap();
|
||||||
|
// TODO: Populate the scores table with details extracted from the
|
||||||
|
// current line. Keep in mind that goals scored by team_1
|
||||||
|
// will be number of goals conceded from team_2, and similarly
|
||||||
|
// goals scored by team_2 will be the number of goals conceded by
|
||||||
|
// team_1.
|
||||||
|
}
|
||||||
|
scores
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn get_results() -> String {
|
||||||
|
let results = "".to_string()
|
||||||
|
+ "England,France,4,2\n"
|
||||||
|
+ "France,Italy,3,1\n"
|
||||||
|
+ "Poland,Spain,2,0\n"
|
||||||
|
+ "Germany,England,2,1\n";
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_scores() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
|
||||||
|
let mut keys: Vec<&String> = scores.keys().collect();
|
||||||
|
keys.sort();
|
||||||
|
assert_eq!(
|
||||||
|
keys,
|
||||||
|
vec!["England", "France", "Germany", "Italy", "Poland", "Spain"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_team_score_1() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
let team = scores.get("England").unwrap();
|
||||||
|
assert_eq!(team.goals_scored, 5);
|
||||||
|
assert_eq!(team.goals_conceded, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_team_score_2() {
|
||||||
|
let scores = build_scores_table(get_results());
|
||||||
|
let team = scores.get("Spain").unwrap();
|
||||||
|
assert_eq!(team.goals_scored, 0);
|
||||||
|
assert_eq!(team.goals_conceded, 2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
# If
|
# If
|
||||||
|
|
||||||
`if`, the most basic type of control flow, is what you'll learn here.
|
`if`, the most basic (but still surprisingly versatile!) type of control flow, is what you'll learn here.
|
||||||
|
|
||||||
## Further information
|
## Further information
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// if1.rs
|
// if1.rs
|
||||||
|
// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -7,7 +8,6 @@ pub fn bigger(a: i32, b: i32) -> i32 {
|
||||||
// Do not use:
|
// Do not use:
|
||||||
// - another function call
|
// - another function call
|
||||||
// - additional variables
|
// - additional variables
|
||||||
// Execute `rustlings hint if1` for hints
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't mind this for now :)
|
// Don't mind this for now :)
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
// Step 1: Make me compile!
|
// Step 1: Make me compile!
|
||||||
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
||||||
// Execute the command `rustlings hint if2` if you want a hint :)
|
// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
pub fn fizz_if_foo(fizzish: &str) -> &str {
|
pub fn foo_if_fizz(fizzish: &str) -> &str {
|
||||||
if fizzish == "fizz" {
|
if fizzish == "fizz" {
|
||||||
"foo"
|
"foo"
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,16 +21,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn foo_for_fizz() {
|
fn foo_for_fizz() {
|
||||||
assert_eq!(fizz_if_foo("fizz"), "foo")
|
assert_eq!(foo_if_fizz("fizz"), "foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bar_for_fuzz() {
|
fn bar_for_fuzz() {
|
||||||
assert_eq!(fizz_if_foo("fuzz"), "bar")
|
assert_eq!(foo_if_fizz("fuzz"), "bar")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_to_baz() {
|
fn default_to_baz() {
|
||||||
assert_eq!(fizz_if_foo("literally anything"), "baz")
|
assert_eq!(foo_if_fizz("literally anything"), "baz")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
mod if1;
|
|
||||||
mod if2;
|
|
|
@ -3,7 +3,11 @@
|
||||||
// We sometimes encourage you to keep trying things on a given exercise, even
|
// 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
|
// 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.
|
// ready for the next exercise, remove the `I AM NOT DONE` comment below.
|
||||||
// Execute the command `rustlings hint intro1` for a hint.
|
// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a hint.
|
||||||
|
//
|
||||||
|
// 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!
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -20,4 +24,7 @@ fn main() {
|
||||||
println!("This exercise compiles successfully. The remaining exercises contain a compiler");
|
println!("This exercise compiles successfully. The remaining exercises contain a compiler");
|
||||||
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!("The source for this exercise is in `exercises/intro/intro1.rs`. Have a look!");
|
||||||
|
println!("Going forward, the source of the exercises will always be in the success/failure output.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// intro2.rs
|
// intro2.rs
|
||||||
// Make the code print a greeting to the world.
|
// Make the code print a greeting to the world.
|
||||||
// Execute `rustlings hint intro2` for a hint.
|
// Execute `rustlings hint intro2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
mod intro1;
|
|
||||||
mod intro2;
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Lifetimes
|
||||||
|
|
||||||
|
Lifetimes tell the compiler how to check whether references live long
|
||||||
|
enough to be valid in any given situation. For example lifetimes say
|
||||||
|
"make sure parameter 'a' lives as long as parameter 'b' so that the return
|
||||||
|
value is valid".
|
||||||
|
|
||||||
|
They are only necessary on borrows, i.e. references,
|
||||||
|
since copied parameters or moves are owned in their scope and cannot
|
||||||
|
be referenced outside. Lifetimes mean that calling code of e.g. functions
|
||||||
|
can be checked to make sure their arguments are valid. Lifetimes are
|
||||||
|
restrictive of their callers.
|
||||||
|
|
||||||
|
## Further information
|
||||||
|
|
||||||
|
- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
|
||||||
|
- [Lifetimes (in Rust By Example)](https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime.html)
|
|
@ -0,0 +1,26 @@
|
||||||
|
// lifetimes1.rs
|
||||||
|
//
|
||||||
|
// 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 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?
|
||||||
|
//
|
||||||
|
// Execute `rustlings hint lifetimes1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
fn longest(x: &str, y: &str) -> &str {
|
||||||
|
if x.len() > y.len() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let string1 = String::from("abcd");
|
||||||
|
let string2 = "xyz";
|
||||||
|
|
||||||
|
let result = longest(string1.as_str(), string2);
|
||||||
|
println!("The longest string is {}", result);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
// lifetimes2.rs
|
||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
if x.len() > y.len() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let string1 = String::from("long string is long");
|
||||||
|
let result;
|
||||||
|
{
|
||||||
|
let string2 = String::from("xyz");
|
||||||
|
result = longest(string1.as_str(), string2.as_str());
|
||||||
|
}
|
||||||
|
println!("The longest string is {}", result);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// lifetimes3.rs
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
struct Book {
|
||||||
|
author: &str,
|
||||||
|
title: &str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let name = String::from("Jill Smith");
|
||||||
|
let title = String::from("Fish Flying");
|
||||||
|
let book = Book { author: &name, title: &title };
|
||||||
|
|
||||||
|
println!("{} by {}", book.title, book.author);
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// macros1.rs
|
// macros1.rs
|
||||||
// Make me compile! Execute `rustlings hint macros1` for hints :)
|
// Execute `rustlings hint macros1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// macros2.rs
|
// macros2.rs
|
||||||
// Make me compile! Execute `rustlings hint macros2` for hints :)
|
// Execute `rustlings hint macros2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// macros3.rs
|
// macros3.rs
|
||||||
// Make me compile, without taking the macro out of the module!
|
// Make me compile, without taking the macro out of the module!
|
||||||
// Execute `rustlings hint macros3` for hints :)
|
// Execute `rustlings hint macros3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// macros4.rs
|
// macros4.rs
|
||||||
// Make me compile! Execute `rustlings hint macros4` for hints :)
|
// Execute `rustlings hint macros4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
mod macros1;
|
|
||||||
mod macros2;
|
|
||||||
mod macros3;
|
|
||||||
mod macros4;
|
|
|
@ -1,26 +0,0 @@
|
||||||
mod advanced_errors;
|
|
||||||
mod clippy;
|
|
||||||
mod collections;
|
|
||||||
mod conversions;
|
|
||||||
mod enums;
|
|
||||||
mod error_handling;
|
|
||||||
mod functions;
|
|
||||||
mod generics;
|
|
||||||
mod r#if;
|
|
||||||
mod intro;
|
|
||||||
mod macros;
|
|
||||||
mod modules;
|
|
||||||
mod move_semantics;
|
|
||||||
mod option;
|
|
||||||
mod primitive_types;
|
|
||||||
mod quiz1;
|
|
||||||
mod quiz2;
|
|
||||||
mod quiz3;
|
|
||||||
mod quiz4;
|
|
||||||
mod standard_library_types;
|
|
||||||
mod strings;
|
|
||||||
mod structs;
|
|
||||||
mod tests;
|
|
||||||
mod threads;
|
|
||||||
mod traits;
|
|
||||||
mod variables;
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod modules1;
|
|
||||||
mod modules2;
|
|
||||||
mod modules3;
|
|
|
@ -1,5 +1,5 @@
|
||||||
// modules1.rs
|
// modules1.rs
|
||||||
// Make me compile! Execute `rustlings hint modules1` for hints :)
|
// Execute `rustlings hint modules1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// modules2.rs
|
// modules2.rs
|
||||||
// You can bring module paths into scopes and provide new names for them with the
|
// 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 compile.
|
// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile.
|
||||||
// Make me compile! Execute `rustlings hint modules2` for hints :)
|
// Execute `rustlings hint modules2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
mod delicious_snacks {
|
mod delicious_snacks {
|
||||||
|
|
||||||
// TODO: Fix these use statements
|
// TODO: Fix these use statements
|
||||||
use self::fruits::PEAR as ???
|
use self::fruits::PEAR as ???
|
||||||
use self::veggies::CUCUMBER as ???
|
use self::veggies::CUCUMBER as ???
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// and especially from the Rust standard library into your scope.
|
// and especially from the Rust standard library into your scope.
|
||||||
// Bring SystemTime and UNIX_EPOCH
|
// Bring SystemTime and UNIX_EPOCH
|
||||||
// from the std::time module. Bonus style points if you can do it with one line!
|
// from the std::time module. Bonus style points if you can do it with one line!
|
||||||
// Make me compile! Execute `rustlings hint modules3` for hints :)
|
// Execute `rustlings hint modules3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
mod move_semantics1;
|
|
||||||
mod move_semantics2;
|
|
||||||
mod move_semantics3;
|
|
||||||
mod move_semantics4;
|
|
||||||
mod move_semantics5;
|
|
||||||
mod move_semantics6;
|
|
|
@ -1,5 +1,5 @@
|
||||||
// move_semantics1.rs
|
// move_semantics1.rs
|
||||||
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
|
// Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// move_semantics2.rs
|
// move_semantics2.rs
|
||||||
// Make me compile without changing line 13 or moving line 10!
|
// Make me compile without changing line 13 or moving line 10!
|
||||||
// Execute `rustlings hint move_semantics2` for hints :)
|
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// move_semantics3.rs
|
// move_semantics3.rs
|
||||||
// Make me compile without adding new lines-- just changing existing lines!
|
// Make me compile without adding new lines-- just changing existing lines!
|
||||||
// (no lines with multiple semicolons necessary!)
|
// (no lines with multiple semicolons necessary!)
|
||||||
// Execute `rustlings hint move_semantics3` for hints :)
|
// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// move_semantics4.rs
|
// move_semantics4.rs
|
||||||
// Refactor this code so that instead of having `vec0` and creating the vector
|
// Refactor this code so that instead of passing `vec0` into the `fill_vec` function,
|
||||||
// in `fn main`, we create it within `fn fill_vec` and transfer the
|
// the Vector gets created in the function itself and passed back to the main
|
||||||
// freshly created vector from fill_vec to its caller.
|
// function.
|
||||||
// Execute `rustlings hint move_semantics4` for hints!
|
// Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// move_semantics5.rs
|
// move_semantics5.rs
|
||||||
// Make me compile only by reordering the lines in `main()`, but without
|
// Make me compile only by reordering the lines in `main()`, but without
|
||||||
// adding, changing or removing any of them.
|
// adding, changing or removing any of them.
|
||||||
// Execute `rustlings hint move_semantics5` for hints :)
|
// Execute `rustlings hint move_semantics5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// move_semantics6.rs
|
// move_semantics6.rs
|
||||||
// Make me compile! `rustlings hint move_semantics6` for hints
|
// Execute `rustlings hint move_semantics6` or use the `hint` watch subcommand for a hint.
|
||||||
// You can't change anything except adding or removing references
|
// You can't change anything except adding or removing references.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
mod option1;
|
|
||||||
mod option2;
|
|
||||||
mod option3;
|
|
|
@ -1,23 +0,0 @@
|
||||||
// option1.rs
|
|
||||||
// Make me compile! Execute `rustlings hint option1` for hints
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
// you can modify anything EXCEPT for this function's signature
|
|
||||||
fn print_number(maybe_number: Option<u16>) {
|
|
||||||
println!("printing: {}", maybe_number.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
print_number(13);
|
|
||||||
print_number(99);
|
|
||||||
|
|
||||||
let mut numbers: [Option<u16>; 5];
|
|
||||||
for iter in 0..5 {
|
|
||||||
let number_to_add: u16 = {
|
|
||||||
((iter * 1235) + 2) / (4 * 16)
|
|
||||||
};
|
|
||||||
|
|
||||||
numbers[iter as usize] = number_to_add;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Option
|
# Options
|
||||||
|
|
||||||
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
||||||
Option types are very common in Rust code, as they have a number of uses:
|
Option types are very common in Rust code, as they have a number of uses:
|
|
@ -0,0 +1,37 @@
|
||||||
|
// options1.rs
|
||||||
|
// Execute `rustlings hint options1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
// you can modify anything EXCEPT for this function's signature
|
||||||
|
fn print_number(maybe_number: Option<u16>) {
|
||||||
|
println!("printing: {}", maybe_number.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// all, so there'll be no more left :(
|
||||||
|
// TODO: Return an Option!
|
||||||
|
fn maybe_icecream(time_of_day: u16) -> Option<u16> {
|
||||||
|
// We use the 24-hour system here, so 10PM is a value of 22
|
||||||
|
???
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_icecream() {
|
||||||
|
assert_eq!(maybe_icecream(10), Some(5));
|
||||||
|
assert_eq!(maybe_icecream(23), None);
|
||||||
|
assert_eq!(maybe_icecream(22), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw_value() {
|
||||||
|
// TODO: Fix this test. How do you get at the value contained in the Option?
|
||||||
|
let icecreams = maybe_icecream(12);
|
||||||
|
assert_eq!(icecreams, 5);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// option2.rs
|
// options2.rs
|
||||||
// Make me compile! Execute `rustlings hint option2` for hints
|
// Execute `rustlings hint options2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// option3.rs
|
// options3.rs
|
||||||
// Make me compile! Execute `rustlings hint option3` for hints
|
// Execute `rustlings hint options3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
mod primitive_types1;
|
|
||||||
mod primitive_types2;
|
|
||||||
mod primitive_types3;
|
|
||||||
mod primitive_types4;
|
|
||||||
mod primitive_types5;
|
|
||||||
mod primitive_types6;
|
|
|
@ -7,6 +7,8 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
// Characters (`char`)
|
// Characters (`char`)
|
||||||
|
|
||||||
|
// Note the _single_ quotes, these are different from the double quotes
|
||||||
|
// you've been seeing around.
|
||||||
let my_first_initial = 'C';
|
let my_first_initial = 'C';
|
||||||
if my_first_initial.is_alphabetic() {
|
if my_first_initial.is_alphabetic() {
|
||||||
println!("Alphabetical!");
|
println!("Alphabetical!");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// primitive_types3.rs
|
// primitive_types3.rs
|
||||||
// Create an array with at least 100 elements in it where the ??? is.
|
// Create an array with at least 100 elements in it where the ??? is.
|
||||||
// Execute `rustlings hint primitive_types3` for hints!
|
// Execute `rustlings hint primitive_types3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// primitive_types4.rs
|
// primitive_types4.rs
|
||||||
// Get a slice out of Array a where the ??? is so that the test passes.
|
// Get a slice out of Array a where the ??? is so that the test passes.
|
||||||
// Execute `rustlings hint primitive_types4` for hints!!
|
// Execute `rustlings hint primitive_types4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// primitive_types5.rs
|
// primitive_types5.rs
|
||||||
// Destructure the `cat` tuple so that the println will work.
|
// Destructure the `cat` tuple so that the println will work.
|
||||||
// Execute `rustlings hint primitive_types5` for hints!
|
// Execute `rustlings hint primitive_types5` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// primitive_types6.rs
|
// primitive_types6.rs
|
||||||
// Use a tuple index to access the second element of `numbers`.
|
// 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.
|
// You can put the expression for the second element where ??? is so that the test passes.
|
||||||
// Execute `rustlings hint primitive_types6` for hints!
|
// Execute `rustlings hint primitive_types6` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
// Put your function here!
|
// Put your function here!
|
||||||
// fn calculate_apple_price {
|
// fn calculate_price_of_apples {
|
||||||
|
|
||||||
// Don't modify this function!
|
// Don't modify this function!
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_test() {
|
fn verify_test() {
|
||||||
let price1 = calculate_apple_price(35);
|
let price1 = calculate_price_of_apples(35);
|
||||||
let price2 = calculate_apple_price(40);
|
let price2 = calculate_price_of_apples(40);
|
||||||
let price3 = calculate_apple_price(65);
|
let price3 = calculate_price_of_apples(65);
|
||||||
|
|
||||||
assert_eq!(70, price1);
|
assert_eq!(70, price1);
|
||||||
assert_eq!(80, price2);
|
assert_eq!(80, price2);
|
||||||
|
|
|
@ -1,30 +1,62 @@
|
||||||
// quiz2.rs
|
// quiz2.rs
|
||||||
// This is a quiz for the following sections:
|
// This is a quiz for the following sections:
|
||||||
// - Strings
|
// - Strings
|
||||||
|
// - Vecs
|
||||||
|
// - Move semantics
|
||||||
|
// - Modules
|
||||||
|
// - Enums
|
||||||
|
|
||||||
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
|
// Let's build a little machine in form of a function.
|
||||||
// task is to call one of these two functions on each value depending on what
|
// As input, we're going to give a list of strings and commands. These commands
|
||||||
// you think each value is. That is, add either `string_slice` or `string`
|
// determine what action is going to be applied to the string. It can either be:
|
||||||
// before the parentheses on each line. If you're right, it will compile!
|
// - Uppercase the string
|
||||||
|
// - Trim the string
|
||||||
|
// - Append "bar" to the string a specified amount of times
|
||||||
|
// The exact form of this will be:
|
||||||
|
// - The input is going to be a Vector of a 2-length tuple,
|
||||||
|
// the first element is the string, the second one is the command.
|
||||||
|
// - The output element is going to be a Vector of strings.
|
||||||
|
// Execute `rustlings hint quiz2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
fn string_slice(arg: &str) {
|
pub enum Command {
|
||||||
println!("{}", arg);
|
Uppercase,
|
||||||
}
|
Trim,
|
||||||
fn string(arg: String) {
|
Append(usize),
|
||||||
println!("{}", arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
mod my_module {
|
||||||
???("blue");
|
use super::Command;
|
||||||
???("red".to_string());
|
|
||||||
???(String::from("hi"));
|
// TODO: Complete the function signature!
|
||||||
???("rust is fun!".to_owned());
|
pub fn transformer(input: ???) -> ??? {
|
||||||
???("nice weather".into());
|
// TODO: Complete the output declaration!
|
||||||
???(format!("Interpolation {}", "Station"));
|
let mut output: ??? = vec![];
|
||||||
???(&String::from("abc")[0..1]);
|
for (string, command) in input.iter() {
|
||||||
???(" hello there ".trim());
|
// TODO: Complete the function body. You can do it!
|
||||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
}
|
||||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// TODO: What to we have to import to have `transformer` in scope?
|
||||||
|
use ???;
|
||||||
|
use super::Command;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let output = transformer(vec![
|
||||||
|
("hello".into(), Command::Uppercase),
|
||||||
|
(" all roads lead to rome! ".into(), Command::Trim),
|
||||||
|
("foo".into(), Command::Append(1)),
|
||||||
|
("bar".into(), Command::Append(5)),
|
||||||
|
]);
|
||||||
|
assert_eq!(output[0], "HELLO");
|
||||||
|
assert_eq!(output[1], "all roads lead to rome!");
|
||||||
|
assert_eq!(output[2], "foobar");
|
||||||
|
assert_eq!(output[3], "barbarbarbarbarbar");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,32 @@
|
||||||
// quiz3.rs
|
// quiz3.rs
|
||||||
// This is a quiz for the following sections:
|
// This quiz tests:
|
||||||
// - Tests
|
// - Generics
|
||||||
|
// - Traits
|
||||||
|
// An imaginary magical school has a new report card generation system written in Rust!
|
||||||
|
// Currently the system only supports creating report cards where the student's grade
|
||||||
|
// is represented numerically (e.g. 1.0 -> 5.5).
|
||||||
|
// However, the school also issues alphabetical grades (A+ -> F-) and needs
|
||||||
|
// to be able to print both types of report card!
|
||||||
|
|
||||||
// This quiz isn't testing our function -- make it do that in such a way that
|
// Make the necessary code changes in the struct ReportCard and the impl block
|
||||||
// the test passes. Then write a second test that tests that we get the result
|
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
||||||
// we expect to get when we call `times_two` with a negative number.
|
// to show that your changes allow alphabetical grades.
|
||||||
// No hints, you can do this :)
|
|
||||||
|
// Execute `rustlings hint quiz3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
pub fn times_two(num: i32) -> i32 {
|
pub struct ReportCard {
|
||||||
num * 2
|
pub grade: f32,
|
||||||
|
pub student_name: String,
|
||||||
|
pub student_age: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReportCard {
|
||||||
|
pub fn print(&self) -> String {
|
||||||
|
format!("{} ({}) - achieved a grade of {}",
|
||||||
|
&self.student_name, &self.student_age, &self.grade)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -18,13 +34,29 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_twice_of_positive_numbers() {
|
fn generate_numeric_report_card() {
|
||||||
assert_eq!(times_two(4), ???);
|
let report_card = ReportCard {
|
||||||
|
grade: 2.1,
|
||||||
|
student_name: "Tom Wriggle".to_string(),
|
||||||
|
student_age: 12,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
report_card.print(),
|
||||||
|
"Tom Wriggle (12) - achieved a grade of 2.1"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_twice_of_negative_numbers() {
|
fn generate_alphabetic_report_card() {
|
||||||
// TODO replace unimplemented!() with an assert for `times_two(-4)`
|
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||||
unimplemented!()
|
let report_card = ReportCard {
|
||||||
|
grade: 2.1,
|
||||||
|
student_name: "Gary Plotter".to_string(),
|
||||||
|
student_age: 11,
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
report_card.print(),
|
||||||
|
"Gary Plotter (11) - achieved a grade of A+"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
// quiz4.rs
|
|
||||||
// This quiz covers the sections:
|
|
||||||
// - Modules
|
|
||||||
// - Macros
|
|
||||||
|
|
||||||
// Write a macro that passes the quiz! No hints this time, you can do it!
|
|
||||||
|
|
||||||
// I AM NOT DONE
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_macro_world() {
|
|
||||||
assert_eq!(my_macro!("world!"), "Hello world!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_macro_goodbye() {
|
|
||||||
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@
|
||||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
// 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`
|
// 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!
|
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
|
||||||
// Execute `rustlings hint arc1` for hints :)
|
// Execute `rustlings hint arc1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
//
|
//
|
||||||
// Note: the tests should not be changed
|
// Note: the tests should not be changed
|
||||||
//
|
//
|
||||||
// Execute `rustlings hint box1` for hints :)
|
// Execute `rustlings hint box1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// This module helps you get familiar with the structure of using an iterator and
|
// This module helps you get familiar with the structure of using an iterator and
|
||||||
// how to go through elements within an iterable collection.
|
// how to go through elements within an iterable collection.
|
||||||
//
|
//
|
||||||
// Execute `rustlings hint iterators1` for hints :D
|
// Execute `rustlings hint iterators1` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// iterators2.rs
|
// 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. Follow the steps to complete the exercise.
|
||||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
// Execute `rustlings hint iterators2` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// 1. Complete the divide function to get the first four tests to pass.
|
// 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
|
// 2. Get the remaining tests to pass by completing the result_with_list and
|
||||||
// list_of_results functions.
|
// list_of_results functions.
|
||||||
// Execute `rustlings hint iterators3` to get some hints!
|
// Execute `rustlings hint iterators3` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ pub struct NotDivisibleError {
|
||||||
|
|
||||||
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
|
// 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> {}
|
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
// Complete the function and return a value of the correct type so the test passes.
|
// Complete the function and return a value of the correct type so the test passes.
|
||||||
// Desired output: Ok([1, 11, 1426, 3])
|
// Desired output: Ok([1, 11, 1426, 3])
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// iterators4.rs
|
// iterators4.rs
|
||||||
|
// Execute `rustlings hint iterators4` or use the `hint` watch subcommand for a hint.
|
||||||
|
|
||||||
// I AM NOT DONE
|
// I AM NOT DONE
|
||||||
|
|
||||||
|
@ -18,6 +19,11 @@ pub fn factorial(num: u64) -> u64 {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn factorial_of_0() {
|
||||||
|
assert_eq!(1, factorial(0));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn factorial_of_1() {
|
fn factorial_of_1() {
|
||||||
assert_eq!(1, factorial(1));
|
assert_eq!(1, factorial(1));
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// imperative style for loops. Recreate this counting functionality using
|
// imperative style for loops. Recreate this counting functionality using
|
||||||
// iterators. Only the two iterator methods (count_iterator and
|
// iterators. Only the two iterator methods (count_iterator and
|
||||||
// count_collection_iterator) need to be modified.
|
// count_collection_iterator) need to be modified.
|
||||||
// Execute `rustlings hint iterators5` for hints.
|
// Execute `rustlings hint iterators5` or use the `hint` watch subcommand for a hint.
|
||||||
//
|
//
|
||||||
// Make the code compile and the tests pass.
|
// Make the code compile and the tests pass.
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
||||||
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 hashmap 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 {
|
||||||
|
@ -52,6 +53,7 @@ fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Pr
|
||||||
// collection is a slice of hashmaps.
|
// collection is a slice of hashmaps.
|
||||||
// collection = [{ "variables1": Complete, "from_str": None, ... },
|
// collection = [{ "variables1": Complete, "from_str": None, ... },
|
||||||
// { "variables2": Complete, ... }, ... ]
|
// { "variables2": Complete, ... }, ... ]
|
||||||
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
mod arc1;
|
|
||||||
mod box1;
|
|
||||||
mod iterators1;
|
|
||||||
mod iterators2;
|
|
||||||
mod iterators3;
|
|
||||||
mod iterators4;
|
|
||||||
mod iterators5;
|
|
|
@ -1,2 +0,0 @@
|
||||||
mod strings1;
|
|
||||||
mod strings2;
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue