mirror of
https://github.com/mainmatter/100-exercises-to-learn-rust
synced 2024-11-16 19:50:44 +01:00
Add CI job to verify that we have no broken links. (#50)
Fix all broken links.
This commit is contained in:
parent
6d707bb32d
commit
f388b2a6c3
11 changed files with 43 additions and 16 deletions
27
.github/workflows/ci.yml
vendored
Normal file
27
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: "CI"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
check-links:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Build book
|
||||
run: |
|
||||
cd book
|
||||
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=.
|
||||
./mdbook build
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@v1
|
||||
with:
|
||||
fail: true
|
||||
args: |
|
||||
--exclude-loopback
|
||||
--require-https
|
||||
--no-progress
|
||||
book/book
|
|
@ -117,7 +117,7 @@ error[E0308]: mismatched types
|
|||
|
|
||||
```
|
||||
|
||||
We'll see how to convert between types [later in this course](../04_traits/09_from).
|
||||
We'll see how to convert between types [later in this course](../04_traits/09_from.md).
|
||||
|
||||
## References
|
||||
|
||||
|
@ -131,8 +131,8 @@ We'll see how to convert between types [later in this course](../04_traits/09_fr
|
|||
|
||||
[^traits]: Rust doesn't let you define custom operators, but it puts you in control of how the built-in operators
|
||||
behave.
|
||||
We'll talk about operator overloading [later in the course](../04_traits/03_operator_overloading), after we've covered traits.
|
||||
We'll talk about operator overloading [later in the course](../04_traits/03_operator_overloading.md), after we've covered traits.
|
||||
|
||||
[^coercion]: There are some exceptions to this rule, mostly related to references, smart pointers and ergonomics. We'll
|
||||
cover those [later on](../04_traits/07_deref).
|
||||
cover those [later on](../04_traits/07_deref.md).
|
||||
A mental model of "all conversions are explicit" will serve you well in the meantime.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Panics
|
||||
|
||||
Let's go back to the `speed` function you wrote for the ["Variables" section](02_variables).
|
||||
Let's go back to the `speed` function you wrote for the ["Variables" section](02_variables.md).
|
||||
It probably looked something like this:
|
||||
|
||||
```rust
|
||||
|
@ -38,7 +38,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
There are other mechanisms to work with recoverable errors in Rust, which [we'll cover later](../05_ticket_v2/06_fallibility).
|
||||
There are other mechanisms to work with recoverable errors in Rust, which [we'll cover later](../05_ticket_v2/06_fallibility.md).
|
||||
For the time being we'll stick with panics as a brutal but simple stopgap solution.
|
||||
|
||||
## References
|
||||
|
|
|
@ -82,7 +82,7 @@ error: literal out of range for `i8`
|
|||
As a rule of thumb, be quite careful with `as` casting.
|
||||
Use it _exclusively_ for going from a smaller type to a larger type.
|
||||
To convert from a larger to smaller integer type, rely on the
|
||||
[*fallible* conversion machinery](../05_ticket_v2/13_try_from) that we'll
|
||||
[*fallible* conversion machinery](../05_ticket_v2/13_try_from.md) that we'll
|
||||
explore later in the course.
|
||||
|
||||
### Limitations
|
||||
|
@ -91,8 +91,8 @@ Surprising behaviour is not the only downside of `as` casting.
|
|||
It is also fairly limited: you can only rely on `as` casting
|
||||
for primitive types and a few other special cases.
|
||||
When working with composite types, you'll have to rely on
|
||||
different conversion mechanisms ([fallible](../05_ticket_v2/13_try_from)
|
||||
and [infallible](../04_traits/09_from)), which we'll explore later on.
|
||||
different conversion mechanisms ([fallible](../05_ticket_v2/13_try_from.md)
|
||||
and [infallible](../04_traits/09_from.md)), which we'll explore later on.
|
||||
|
||||
## References
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ let ticket = Ticket {
|
|||
You've seen this in action in the previous exercise on visibility.
|
||||
We now need to provide one or more public **constructors**—i.e. static methods or functions that can be used
|
||||
from outside the module to create a new instance of the struct.
|
||||
Luckily enough we already have one: `Ticket::new`, as implemented in [a previous exercise](02_validation).
|
||||
Luckily enough we already have one: `Ticket::new`, as implemented in [a previous exercise](02_validation.md).
|
||||
|
||||
## Accessor methods
|
||||
|
||||
|
@ -60,4 +60,4 @@ You have to write them yourself—they're just regular methods.
|
|||
|
||||
- The exercise for this section is located in `exercises/03_ticket_v1/05_encapsulation`
|
||||
|
||||
[^newtype]: Or refine their type, a technique we'll explore [later on](../05_ticket_v2/15_outro).
|
||||
[^newtype]: Or refine their type, a technique we'll explore [later on](../05_ticket_v2/15_outro.md).
|
|
@ -49,6 +49,6 @@ They just point to a memory location, which _may_ be on the heap, but doesn't ha
|
|||
|
||||
- The exercise for this section is located in `exercises/03_ticket_v1/10_references_in_memory`
|
||||
|
||||
[^fat]: [Later in the course](../04_traits/06_str_slice) we'll talk about **fat pointers**,
|
||||
[^fat]: [Later in the course](../04_traits/06_str_slice.md) we'll talk about **fat pointers**,
|
||||
i.e. pointers with additional metadata. As the name implies, they are larger than
|
||||
the pointers we discussed in this chapter, also known as **thin pointers**.
|
||||
|
|
|
@ -166,7 +166,7 @@ Follow Rust's conventions though: use camel case for type parameter names.
|
|||
|
||||
You may wonder why we need trait bounds at all. Can't the compiler infer the required traits from the function's body?
|
||||
It could, but it won't.
|
||||
The rationale is the same as for [explicit type annotations on function parameters](../02_basic_calculator/02_variables#function-arguments-are-variables):
|
||||
The rationale is the same as for [explicit type annotations on function parameters](../02_basic_calculator/02_variables.md#function-arguments-are-variables):
|
||||
each function signature is a contract between the caller and the callee, and the terms must be explicitly stated.
|
||||
This allows for better error messages, better documentation, less unintentional breakages across versions,
|
||||
and faster compilation times.
|
||||
|
|
|
@ -6,7 +6,7 @@ From our previous [discussion on memory layouts](../03_ticket_v1/10_references_i
|
|||
it would have been reasonable to expect `&str` to be represented as a single `usize` on
|
||||
the stack, a pointer. That's not the case though. `&str` stores some **metadata** next
|
||||
to the pointer: the length of the slice it points to. Going back to the example from
|
||||
[a previous section](06_str_slice):
|
||||
[a previous section](06_str_slice.md):
|
||||
|
||||
```rust
|
||||
let mut s = String::with_capacity(5);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# The `Drop` trait
|
||||
|
||||
When we introduced [destructors](../03_ticket_v1/11_destructor),
|
||||
When we introduced [destructors](../03_ticket_v1/11_destructor.md),
|
||||
we mentioned that the `drop` function:
|
||||
|
||||
1. reclaims the memory occupied by the type (i.e. `std::mem::size_of` bytes)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Enumerations
|
||||
|
||||
Based on the validation logic you wrote [in a previous chapter](../03_ticket_v1/02_validation),
|
||||
Based on the validation logic you wrote [in a previous chapter](../03_ticket_v1/02_validation.md),
|
||||
there are only a few valid statuses for a ticket: `To-Do`, `InProgress` and `Done`.
|
||||
This is not obvious if we look at the `status` field in the `Ticket` struct or at the type of the `status`
|
||||
parameter in the `new` method:
|
||||
|
|
|
@ -102,7 +102,7 @@ async fn run() {
|
|||
|
||||
- Be extremely careful when using `tokio`'s `select!` macro to "race" two different futures.
|
||||
Retrying the same task in a loop is dangerous unless you can ensure **cancellation safety**.
|
||||
Check out [`select!`'s documentation](https://docs.rs/tokio/macro.select.html) for more details.
|
||||
Check out [`select!`'s documentation](https://tokio.rs/tokio/tutorial/select) for more details.
|
||||
If you need to interleave two asynchronous streams of data (e.g. a socket and a channel), prefer using
|
||||
[`StreamExt::merge`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.merge) instead.
|
||||
- Rather than "abrupt" cancellation, it can be preferable to rely
|
||||
|
|
Loading…
Reference in a new issue