Skip to content

Commit f60aed7

Browse files
committed
Question improvements
1 parent 04fbdda commit f60aed7

File tree

3 files changed

+72
-23
lines changed

3 files changed

+72
-23
lines changed

questions/q107.yaml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,32 @@ expected_output:
3030
explanation: |-
3131
This question tests understanding of error handling with `Result`, the `map_err`
3232
combinator, and how collecting an iterator of `Result` values works.
33-
33+
3434
The `parse_and_double` function attempts to parse a string into an `i32`,
3535
doubles it if successful, and transforms any parse error into a custom error
3636
message using `map_err`. The `map_err` combinator only executes when there's an
3737
`Err` variant, transforming the error type from `ParseIntError` to `String`.
38-
38+
3939
When the code processes the inputs:
4040
1. `"5"` parses successfully to `5`, which is doubled to `10`, resulting in
41-
`Ok(10)`
41+
`Ok(10)`
4242
2. `"not a number"` fails to parse, producing an error that `map_err` transforms
43-
into `Err("Parse failed: invalid digit found in string")`
43+
into `Err("Parse failed: invalid digit found in string")`
4444
3. `"10"` is never processed
45-
45+
4646
The key behavior is how `collect()` works with `Result` types. When collecting
4747
an iterator of `Result<T, E>` into `Result<Vec<T>, E>`, Rust implements
4848
short-circuit semantics: the collection stops at the first error encountered and
4949
returns that error immediately. This is an "all-or-nothing" pattern where either
5050
all operations succeed (producing `Ok(vec)`) or any failure causes the entire
5151
operation to fail with the first error.
52-
52+
53+
Note that if we collected into `Vec<Result<i32, String>>` instead, we would get
54+
`[Ok(10), Err("Parse failed: invalid digit found in string"), Ok(20)]`,
55+
preserving all results. The choice of collection type determines whether errors
56+
short-circuit or are collected alongside successes.
57+
5358
The key takeaway is that collecting `Result` values provides fail-fast
5459
semantics, which is useful for validation scenarios where partial success is not
5560
acceptable. The `map_err` combinator is valuable for adding context to errors or
56-
converting between error types while preserving the success values unchanged.
61+
converting between error types while preserving the success values unchanged.

questions/q162.yaml

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ question: |-
55
fn main() {
66
let paths = vec![
77
"/usr/bin/../lib/file.so",
8-
"relative/../path/to/file",
8+
"relative/path/../file",
99
"../../../etc/passwd",
1010
"normal/path/file.txt"
1111
];
@@ -23,14 +23,14 @@ question: |-
2323
2424
What does this code print?
2525
answers:
26-
- All print `Some("file")` as the parent directory name
27-
- First prints `Some("lib")`, second prints `Some("to")`, third prints `Some("etc")`, fourth prints `Some("path")`
28-
- First prints `Some("lib")`, second prints `Some("to")`, third prints `None`, fourth prints `Some("path")`
26+
- '`Some("file.so")`, `Some("file")`, `Some("passwd")`, `Some("file.txt")`'
27+
- '`Some("lib")`, `None`, `Some("etc")`, `Some("path")`'
28+
- '`Some("lib")`, `Some("..")`, `Some("etc")`, `Some("path")`'
2929
- All print `None` because parent directories cannot be determined from strings
3030
correct_answer: 1
3131
expected_output:
3232
- '/usr/bin/../lib/file.so: Some("lib")'
33-
- 'relative/../path/to/file: Some("to")'
33+
- 'relative/path/../file: None'
3434
- '../../../etc/passwd: Some("etc")'
3535
- 'normal/path/file.txt: Some("path")'
3636
explanation: |-
@@ -44,21 +44,16 @@ explanation: |-
4444
For `/usr/bin/../lib/file.so`, the parent is `/usr/bin/../lib`, and its file
4545
name component is `lib`, resulting in `Some("lib")`.
4646
47-
For `relative/../path/to/file`, the parent is `relative/../path/to`, and its
48-
file name component is `to`, resulting in `Some("to")`.
47+
For `relative/path/../file`, the parent is `relative/path/..`. The final
48+
component `..` is not a valid file name, so the result is `None`.
4949
50-
For `../../../etc/passwd`, the parent is `../../../etc`. Rust's `Path` API
51-
performs lexical (string-based) path operations. When extracting the file name
52-
from `../../../etc`, it treats `etc` as a regular path component and returns
53-
`Some("etc")`. The `..` components earlier in the path don't affect the file
54-
name extraction of the final component.
50+
For `../../../etc/passwd`, the parent is `../../../etc`, and its file name
51+
component is `etc`, resulting in `Some("etc")`.
5552
5653
For `normal/path/file.txt`, the parent is `normal/path`, and its file name
5754
component is `path`, resulting in `Some("path")`.
5855
5956
The key takeaway is that Rust's `Path` API performs lexical operations without
6057
filesystem access or path normalization. The `file_name()` method extracts the
61-
final component of a path as a string operation, treating each segment between
62-
separators as a distinct component. Path components like `..` are treated as
63-
regular components in the path string, and `file_name()` simply returns the last
64-
non-empty component.
58+
final component of a path, but returns `None` for special components like `..`
59+
and `.`, as these are not considered valid file names.

questions/q343.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
question: |-
2+
```rust
3+
fn parse_and_double(s: &str) -> Result<i32, String> {
4+
s.parse::<i32>()
5+
.map(|n| n * 2)
6+
.map_err(|e| format!("Parse failed: {}", e))
7+
}
8+
9+
fn main() {
10+
let inputs = vec!["5", "not a number", "10"];
11+
12+
let result: Vec<Result<i32, String>> = inputs
13+
.iter()
14+
.map(|s| parse_and_double(s))
15+
.collect();
16+
17+
println!("{:?}", result);
18+
}
19+
```
20+
21+
What does this print?
22+
answers:
23+
- 'Err("Parse failed: invalid digit found in string")'
24+
- '[Ok(10), Err("Parse failed: invalid digit found in string"), Ok(20)]'
25+
- '[Ok(10), Err("Parse failed: invalid digit found in string")]'
26+
- 'Compilation error: cannot collect iterator of `Result` into `Vec<Result<_, _>>`'
27+
correct_answer: 1
28+
expected_output:
29+
- '[Ok(10), Err("Parse failed: invalid digit found in string"), Ok(20)]'
30+
explanation: |-
31+
This question tests understanding of how collecting `Result` values into different
32+
container types affects error handling behavior.
33+
34+
When the code processes the inputs:
35+
1. `"5"` parses successfully to `5`, doubled to `10`: `Ok(10)`
36+
2. `"not a number"` fails to parse: `Err("Parse failed: invalid digit found in string")`
37+
3. `"10"` parses successfully to `10`, doubled to `20`: `Ok(20)`
38+
39+
When collecting into `Vec<Result<T, E>>`, all elements are processed without
40+
short-circuiting. Each result is preserved in the vector, allowing both successes
41+
and failures to coexist. All three results appear in the final vector.
42+
43+
Note that if we collected into `Result<Vec<T>, E>` instead, the iterator would
44+
short-circuit at the first error and return `Err("Parse failed: invalid digit
45+
found in string")`, never processing the third element.
46+
47+
The key takeaway is that the collection target type determines error handling:
48+
`Vec<Result<T, E>>` collects all results including errors, while `Result<Vec<T>, E>`
49+
provides fail-fast semantics that stop at the first error.

0 commit comments

Comments
 (0)