mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 08:38:09 -05:00
Wording tweaks
This commit is contained in:
parent
ac1d473ac2
commit
f7a5fea93d
@ -75,16 +75,20 @@ we'll follow this guide:
|
||||
- Boxed closures (FnBox, others?) are heap allocated
|
||||
- "Move" semantics don't trigger new allocation; just a change of ownership,
|
||||
so are incredibly fast
|
||||
- In examples, is address of data before and after the same?
|
||||
- Can `Copy` trigger allocation?
|
||||
- Stack-based alternatives to standard library types should be preferred (spin, parking_lot)
|
||||
|
||||
## Smart pointers
|
||||
# Smart pointers
|
||||
|
||||
The first thing to note are the "smart pointer" types.
|
||||
When you have data that must outlive the scope in which it is declared,
|
||||
or your data is of unknown or dynamic size, you'll make use of these types.
|
||||
|
||||
The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer)
|
||||
comes from C++, and is used to describe objects that are responsible for managing
|
||||
comes from C++, and while it's closely linked to a general design pattern of
|
||||
["Resource Acquisition Is Initialization"](https://en.cppreference.com/w/cpp/language/raii),
|
||||
we'll use it here specifically to describe objects that are responsible for managing
|
||||
ownership of data allocated on the heap. The smart pointers available in the `alloc`
|
||||
crate should look mostly familiar:
|
||||
- [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
|
||||
@ -97,10 +101,10 @@ though more than can be covered in this article. Some examples:
|
||||
- [`RwLock`](https://doc.rust-lang.org/std/sync/struct.RwLock.html)
|
||||
- [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
|
||||
|
||||
Finally, there is one [gotcha](https://www.merriam-webster.com/dictionary/gotcha):
|
||||
Finally, there is one ["gotcha"](https://www.merriam-webster.com/dictionary/gotcha):
|
||||
cell types (like [`RefCell`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html))
|
||||
look and behave like smart pointers, but don't actually require heap allocation.
|
||||
Check out the [`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
|
||||
follow the RAII pattern, but don't involve heap allocation. Check out the
|
||||
[`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
|
||||
for more information.
|
||||
|
||||
When a smart pointer is created, the data it is given is placed in heap memory and
|
||||
@ -138,7 +142,7 @@ pub fn my_cow() {
|
||||
```
|
||||
-- [Compiler Explorer](https://godbolt.org/z/SaDpWg)
|
||||
|
||||
## Collections
|
||||
# Collections
|
||||
|
||||
Collections types use heap memory because they have dynamic size; they will request more memory
|
||||
[when needed](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve),
|
||||
|
@ -30,7 +30,7 @@ we're just focused on interesting things the Rust language can do.
|
||||
The guiding principal as we move forward is this: *optimizing compilers
|
||||
won't produce worse assembly than we started with.* There won't be any
|
||||
situations where stack allocations get moved to heap allocations.
|
||||
There will, however, be an opera of optimization.
|
||||
There will, however, be an opera of optimization.
|
||||
|
||||
# The Case of the Disappearing Box
|
||||
|
||||
|
@ -99,7 +99,7 @@ With all that in mind, let's talk about situations in which we're guaranteed to
|
||||
- Closures capture their arguments on the stack
|
||||
- Generics will use stack allocation, even with dynamic dispatch.
|
||||
|
||||
## Structs
|
||||
# Structs
|
||||
|
||||
The simplest case comes first. When creating vanilla `struct` objects, we use stack memory
|
||||
to hold their contents:
|
||||
@ -132,7 +132,7 @@ pub fn make_line() {
|
||||
Note that while some extra-fancy instructions are used for memory manipulation in the assembly,
|
||||
the `sub rsp, 64` instruction indicates we're still working with the stack.
|
||||
|
||||
## Function arguments
|
||||
# Function arguments
|
||||
|
||||
Have you ever wondered how functions communicate with each other? Like, once the variables are
|
||||
given to you, everything's fine. But how do you "give" those variables to another function?
|
||||
@ -237,7 +237,7 @@ and passing by reference (either moving ownership or passing a pointer) may have
|
||||
[slightly different layouts in assembly](https://godbolt.org/z/sKi_kl), but will
|
||||
still use either stack memory or CPU registers.
|
||||
|
||||
## Enums
|
||||
# Enums
|
||||
|
||||
If you've ever worried that wrapping your types in
|
||||
[`Option`](https://doc.rust-lang.org/stable/core/option/enum.Option.html) or
|
||||
@ -275,7 +275,7 @@ in assembly, so I'll instead point you to the
|
||||
[`core::mem::size_of`](https://doc.rust-lang.org/stable/core/mem/fn.size_of.html#size-of-enums)
|
||||
documentation.
|
||||
|
||||
## Arrays
|
||||
# Arrays
|
||||
|
||||
The array type is guaranteed to be stack allocated, which is why the array size must
|
||||
be declared. Interestingly enough, this can be used to cause safe Rust programs to crash:
|
||||
@ -320,7 +320,7 @@ There aren't any security implications of this (no memory corruption occurs),
|
||||
but it's good to note that the Rust compiler won't move arrays into heap memory
|
||||
even if they can be reasonably expected to overflow the stack.
|
||||
|
||||
## Closures
|
||||
# Closures
|
||||
|
||||
Rules for how anonymous functions capture their arguments are typically language-specific.
|
||||
In Java, [Lambda Expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
|
||||
@ -387,7 +387,7 @@ pub fn complex() {
|
||||
|
||||
In every circumstance though, the compiler ensured that no heap allocations were necessary.
|
||||
|
||||
## Generics
|
||||
# Generics
|
||||
|
||||
Traits in Rust come in two broad forms: static dispatch (monomorphization, `impl Trait`)
|
||||
and dynamic dispatch (trait objects, `dyn Trait`). While dynamic dispatch is often
|
||||
@ -444,5 +444,5 @@ pub fn do_call() {
|
||||
```
|
||||
-- [Compiler Explorer](https://godbolt.org/z/u_yguS)
|
||||
|
||||
It's hard to imagine practical situations where dynamic dispatch
|
||||
would be used for objects that aren't heap allocated, but it can be done.
|
||||
It's hard to imagine practical situations where dynamic dispatch would be
|
||||
used for objects that aren't heap allocated, but it technically can be done.
|
@ -16,7 +16,7 @@ we'll go into below. The
|
||||
[full specification](https://github.com/rust-lang/rfcs/blob/master/text/0246-const-vs-static.md)
|
||||
for these two memory types is available, but we'll take a hands-on approach to the topic.
|
||||
|
||||
## **const**
|
||||
# **const**
|
||||
|
||||
The quick summary is this: `const` declares a read-only block of memory that is loaded
|
||||
as part of your program binary (during the call to [exec(3)](https://linux.die.net/man/3/exec)).
|
||||
@ -144,7 +144,7 @@ but the specifications are clear enough: *don't rely on pointers to `const`
|
||||
values being consistent*. To be frank, caring about locations for `const` values
|
||||
is almost certainly a code smell.
|
||||
|
||||
## **static**
|
||||
# **static**
|
||||
|
||||
Static variables are related to `const` variables, but take a slightly different approach.
|
||||
When the compiler can guarantee that a *reference* is fixed for the life of a program,
|
||||
|
Loading…
Reference in New Issue
Block a user