Nearly a week into the journey, I feel I've learned a good amount - I hope you have too. I'm at a point where I want to start coding something more substantial. I just finished the last quarter of this YouTube tutorial. Now that's done, I can pivot to a pet project 💪 🐶
Tomorrow I'll summarize what how far we've come and what's next.
Yesterday's questions answered
- The only safe API to casts in Rust is the
as
keyword. -
Correction from yesterday: I wrote deconstructors where I meant destructors :) The closest thing Rust has to a
destructor
is theDrop
trait. This allows programmers to define the clean up behaviour when an variable goes out of scope. You cannot call this explicitly, Rust handles that. Pointers do have adrop_in_place
method that allows explicit destruction.
Today's open questions
- What exactly does a
Box
tell the compiler? - What on earth are
Arc
andMutex
types???? - I want to try a more practical example of threading, are there any design patterns or higher-level APIs to do this?
- How does the
where
syntax work and where do I use it? - Does
closure
types have other good features other than accessing variables outside the current scope?
Close the pipes |
Rust is one of the many languages that supports anonymous-ish functions. JavaScript has its arrow function expressions
; Python has is ugly lambda
functions. A better Python feature is the partial
function which lets you bind arguments preemptively to a function which can be called at an arbitrary moment later at runtime: useful for mocking, multiprocessing and so on.
Rust calls its equivalent a closure
. There are at least three cool things about a closure
:
- It can be passed as an argument to a function. The if the receiving function is a generic, if must use a
where
clause, which I think is used to match a generic to a type. - They can access variables outside of the scope they are in. This means you can process stuff outside of your current scope without carrying references to it down, which could be useful if you are 3/4 blocks deep in the call stack.
- You can declare a
closure
using two trusty|
operators:
let be_nice_to_johnny: &str = "Guten Tag";
let greet_johnny = |greeting: &str| {
println!(
"This greeting `{}` isn't nice enough for Johnny. Try instead: {}, Johnny!",
greeting, be_nice_to_johnny
);
};
greet_johnny("Moin");
Why pipes | Is this some Rust hipster trash?
Until now most of our encounters with functions involved parentheses and curly braces. Why do we need a shiny new character to add to our cognitive load?
If we go back to the first and second cool things about a closure
, we can see that a closure
is effectively able to |
a variable from one scope to the next. This makes me consider whether rust developers typically use a closure
as wrapper around a variable. My first impression is: that would be bad. But we still have a long way to go before forming valid opinions.
One thing to remember is that if you want to change the values stored at the reference, both the closure
and the variable must declared as mut
.
Threading the | of a needle
If you want to spawn
a thread in Rust, you need to provide a closure
as an argument. I only touched on threads briefly today. You can .join
a thread to ensure that is runs even after the main thread has finished. And you need to .unwrap
the result of a .join
.
Resource management for threads is often abstracted away for developers like me. Rust seems to do this using different kinds of pointers (Arc
and Mutex
) for example. I'm not sure what exactly is going on under the hood, that's on the todo list. But wrapping your variables in these types can help you to quickly implement basic threading use cases.
Rust is such a (brown) box of a language
If threading wasn't enough for a Friday, I also got a pleasant introduction to Box
types. A Box
will help rust to store pointers to a data on the heap. I didn't go into any depth here and need to understand more of the internals. But Box
is an API to abstract some aspect of memory management.
Top comments (0)