mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 04:54:17 -06:00
finished ch20.1
This commit is contained in:
parent
6aa4deab15
commit
5da2a5c2b5
20
.obsidian/workspace.json
vendored
20
.obsidian/workspace.json
vendored
@ -63,6 +63,20 @@
|
||||
"title": "Advanced Features"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8efdb57e394f2650",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Advanced Traits.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "Advanced Traits"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8cdde5c4be386d20",
|
||||
"type": "leaf",
|
||||
@ -130,7 +144,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 4
|
||||
"currentTab": 3
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
@ -273,8 +287,9 @@
|
||||
"command-palette:Open command palette": false
|
||||
}
|
||||
},
|
||||
"active": "8cdde5c4be386d20",
|
||||
"active": "de2ac5df5b921166",
|
||||
"lastOpenFiles": [
|
||||
"Advanced Traits.md",
|
||||
"Advanced Features.md",
|
||||
"Unsafe Rust.md",
|
||||
"Pattern Matching.md",
|
||||
@ -300,7 +315,6 @@
|
||||
"Passing Data Between Threads.md",
|
||||
"Leaky Reference Cycles.md",
|
||||
"Test Controls.md",
|
||||
"Ref Cell Mutability.md",
|
||||
"minigrep/src/lib.rs",
|
||||
"does_not_compile.svg",
|
||||
"Untitled.canvas",
|
||||
|
@ -9,7 +9,7 @@ The features covered here are useful in very specific situations.
|
||||
|
||||
In this chapter we will cover
|
||||
- [Unsafe Rust](./Unsafe%20Rust.md): How to opt out of some of Rust's guarantees and take responsibility for manually upholding those guarantees
|
||||
- [Advanced traits](): associated types, default type parameters, fully qualified syntax, supertraits, and the new type pattern in relation to traits
|
||||
- [Advanced traits](./Advanced%20Traits.md): associated types, default type parameters, fully qualified syntax, supertraits, and the new type pattern in relation to traits
|
||||
- [Advanced types](): more about the newtype pattern, type aliases, the never type, and dynamically sized types
|
||||
- [Advanced functions and closures](): function pointers and returning closures
|
||||
- [Macros](): ways to define code that defines more code at compile time
|
||||
|
1
Advanced Traits.md
Normal file
1
Advanced Traits.md
Normal file
@ -0,0 +1 @@
|
||||
# Advanced Traits
|
133
Unsafe Rust.md
133
Unsafe Rust.md
@ -450,3 +450,136 @@ fn main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
Just like with regular variables, we specify mutability using the `mut` keyword.
|
||||
|
||||
Any code that reads or writes from `COUNTER` must be within an `unsafe` block.
|
||||
|
||||
The code above compiles and prints `COUNTER: 3` as expected because it is single threaded.
|
||||
|
||||
Having multiple thread access `COUNTER` would likely result in data races, so it is undefined behavior.
|
||||
|
||||
Due to this we need to mark the entire function as `unsafe` and document the safety limitation, so anyone calling this function knows what they are and are not allowed to do safely.
|
||||
|
||||
Whenever we write an unsafe function, it is idiomatic to write a comment starting with `SAFETY` and explaining what the caller needs to do to call the function safely.
|
||||
|
||||
Also whenever we perform an unsafe operation it is idiomatic to write a comment starting with `SAFETY` to explain how the safety rules are upheld.
|
||||
|
||||
As well, the compiler will not allow you to create references to a mutable static variable.
|
||||
|
||||
You can only access it via a raw pointer, created with one of the raw borrow operators.
|
||||
|
||||
This includes in cases where the reference is created invisibly as when it is used in the `println!` in this code listing.
|
||||
|
||||
The requirement that references to static mutable variables can only be created via raw pointers helps make the safety requirements for using them more obvious.
|
||||
|
||||
With mutable data that is globally accessible, it is difficult to ensure that there are no data races, which is why Rust considers mutable static variables to be unsafe.
|
||||
|
||||
Where it is possible it is preferred to use concurrency techniques and thread-safe smart pointers, so the compiler checks that data accessed from different threads is done safely.
|
||||
|
||||
## Implementing an Unsafe Trait
|
||||
Additionally `unsafe` to implement an unsafe trait.
|
||||
|
||||
A trait is unsafe when at least one of its methods has some invariant that the compiler can't verify.
|
||||
|
||||
We declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait` and marking the implementation of the trait as `unsafe` too.
|
||||
|
||||
Here is an example of this
|
||||
```rust
|
||||
unsafe trait Foo {
|
||||
// methods go here
|
||||
}
|
||||
|
||||
unsafe impl Foo for i32 {
|
||||
// method implementations go here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
By using `unsafe impl`, we are promising that we will uphold the invariants that the compiler can't verify.
|
||||
|
||||
As an example, recall the `Sync` and `Send` marker traits we discussed in ["Extensible Concurrency with the `Sync` and `Send` Traits"]() section.
|
||||
|
||||
The compiler implements these traits automatically if our types are composed entirely of `Send` and `Sync` types.
|
||||
|
||||
If we implement a type that contains a type that is not `Send` or `Sync`, such as raw pointers, and we want to mark that type as `Send` or `Sync`, we must use `unsafe`.
|
||||
|
||||
Rust can't verify that our type upholds the guarantees that it can be safely sent across threads or accessed form multiple threads.
|
||||
|
||||
We need to do these checks manually and indicate as such with `unsafe`.
|
||||
|
||||
## Accessing Fields of a Union
|
||||
The last superpower that works on with `unsafe` is accessing fields of a *union*.
|
||||
|
||||
A `union` is similar to a `struct`, but only one declared field is used in a particular instance at one time.
|
||||
|
||||
Unions are primarily used to interface with unions in C code.
|
||||
|
||||
Accessing union fields is unsafe because Rust can't guarantee the type of data currently being stored in the union instance.
|
||||
|
||||
You can learn more about unions in [the Rust Reference](https://doc.rust-lang.org/reference/items/unions.html).
|
||||
|
||||
## Using Miri to check unsafe code
|
||||
When writing unsafe code, you may want to check that you have written actually is safe and correct.
|
||||
|
||||
Using [Miri](https://github.com/rust-lang/miri), an official Rust tool for detecting undefined behavior is one of the best ways to do it.
|
||||
|
||||
While the borrow checker is a *static* tool which works at compile time, Miri is a *dynamic* tool which works at runtime.
|
||||
|
||||
It checks your code by running your program or its test suite and detecting when you violate the rules it understands about how Rust should work.
|
||||
|
||||
Miri requires a nightly build of Rust (discussed in [Appendix G: How Rust is Made and "Nightly Rust"](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)).
|
||||
|
||||
You can install both a nightly version of Rust and the Miri tool by typing `rustup +nightly component add miri`.
|
||||
|
||||
This does not change what version of Rust your project uses.
|
||||
|
||||
This only adds the tool to your system so you can use it when you want to.
|
||||
|
||||
You can run Miri on a project by typing cargo `+nightly miri run` or `cargo +nightly miri test`.
|
||||
|
||||
Here is an example of how useful when we run it on a previous example
|
||||
```
|
||||
$ cargo +nightly miri run
|
||||
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
|
||||
Running `/Users/chris/.rustup/toolchains/nightly-aarch64-apple-darwin/bin/cargo-miri runner target/miri/aarch64-apple-darwin/debug/unsafe-example`
|
||||
warning: creating a shared reference to mutable static is discouraged
|
||||
--> src/main.rs:14:33
|
||||
|
|
||||
14 | println!("COUNTER: {}", COUNTER);
|
||||
| ^^^^^^^ shared reference to mutable static
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
|
||||
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
|
||||
= note: `#[warn(static_mut_refs)]` on by default
|
||||
|
||||
COUNTER: 3
|
||||
```
|
||||
It helpfully and correctly notices that we have shared references to mutable data and warns about it.
|
||||
|
||||
Here it does not tell us how to fix the problem, but it mean that we know there is a possible issue and can think about how to make sure it is safe.
|
||||
|
||||
In other cases, it can actually tell us that some code is *sure* to be wrong and make recommendations about how to fix it.
|
||||
|
||||
Miri will not catch *everything* you may get wrong when writing unsafe code.
|
||||
|
||||
Since it is a dynamic check, it only catches problems with code that actually gets run.
|
||||
|
||||
This means you will need to use it with good testing techniques to increase your confidence about the unsafe code you have written.
|
||||
|
||||
Additionally it does not cover every possible way your code can be unsound.
|
||||
|
||||
If Miri *does* catch a problem, you know that there is a bug, but just because Miri *doesn't* catch a bug doesn't mean there isn't a problem.
|
||||
|
||||
Miri can catch a lot despite this.
|
||||
|
||||
## When to Use Unsafe Code
|
||||
Using `unsfe` to take one of the five superpowers, isn't wrong or frowned upon.
|
||||
|
||||
But it is trickier to get `unsafe` code correct because the compiler can't help uphold memory safety.
|
||||
|
||||
When you have a reason to use `unsafe` code, you can do so and having the explicit `unsafe` annotation makes it easier to tack down the source of problems when they occur.
|
||||
|
||||
When you write unsafe code, you can use Miri to help to be more confident that the code you wrote upholds Rust's rules.
|
||||
|
||||
For a deeper exploration of how to work effectively with unsafe Rust, read Rust's official guide on the subject the [Rustonomicon](https://doc.rust-lang.org/nomicon/).
|
Loading…
x
Reference in New Issue
Block a user