DEV Community

Cover image for 30 Days of Rust - Day 7
johnnylarner
johnnylarner

Posted on • Edited on

30 Days of Rust - Day 7

After a week of learning, I'm going to dedicate this blog article to reflecting on what we've learned so far. Before that though here are a few fun facts:

  1. The blog series has had over 300 views so far - so THANKS for that :)
  2. If you've read every article in the series, that's over 4500 words.
  3. Together we've asked and answered 30 questions about Rust.

To break from tradition, I won't be asking any questions today. Tomorrow I'll sketch out what I'm planning for the next week of the series 💪

Yesterday's questions answered

  • All values are by default stack-allocated in Rust. Box is a way to tell the compiler to put a value on the heap. This makes a Box a smart pointer. Values should be added to the heap when they are expected to grow or be shared of multiple threads.
  • An Arc is a smart pointer that manages multiple atomic references to a value on a heap. In using an Arc, a developer can guarantee thread safety for access to a value. To manipulate values references by an Arc, you need to first wrap the value in a Mutex before wrapping it in an Arc.
  • A Mutex guarantees single-thread access to a value using the .lock method. This enables threads to update values at a given reference safely.
  • Having scanned the Rust book, I couldn't find a high-level API for thread management. I did learn about the channel concept which enables threads to pass messages to one another.
  • The where clause is used to improve bounding for traits during generic declarations. The documentation is lacking here and I think it's probably okay to drop this topic for now.
  • I couldn't find other exciting features for a closure. But I learned that Rust's compiler will type a closure depending on whether it uses variables referenced in another scope.

7 Days of Rust in 45 seconds

Project management

Depend on Rust's package manager cargo:

cargo new <project_name> # Project init
cargo build; cargo compile; cargo run; # Build and run stuff
cargo add <library> # Add dependencies
cargo test # Run your tests
Enter fullscreen mode Exit fullscreen mode

Im- / export your Rust

Declare crates consisting of mods inside of a public function to make code exportable:

pub fn my_crate() {
    crate::module_root::to::module()
}
Enter fullscreen mode Exit fullscreen mode

The same :: colon syntax is used to import crates and their submodules. You can import wildcards, a single or multiple module members.

Indeed I do declare

  • let and const for variable and constants.
  • mut follows let if you want to make something mutable.

Control the flow

  • Rust supports if/else statements as well as match statements.
  • Tend towards match over if as match is used in several Rust patterns.
  • You can loop with loop, for and while. Opt for loop if you need to use uninitialised variables or want a returned value from break.
  • Use .iter method on collections when iterating to get references to its values.

The important data types

  • Use arrays and tuples for fixed size collections of single and mixed types, respectively.
  • Use Vec for a growable collection.
  • Favour String over read-only &str
  • HashMaps for single-typed lookups, structs for logical data groups, enum for categories
  • Use traits to define interfaces for structs

DaFunc?

  • Declare functions with fn
  • Functions are scoped and will shadow variables outside of their scope
  • Omit return and trailing ; to do an implicit return
  • Anonymous functions are declared using two pipe operators and are called a closure
  • closures can access variables declared at the same level as them inside their body. Use them for threading!

Pointing out the not obvious

  • Static values are stored on the stack, dynamic, unknown or recursive structures are stored on the heap.
  • Each value on the heap in Rust can only have one owner, thus reassigning a variable to a new variable will relinquish the latter of its ownership.
  • Each value has a scope and it will be dropped once that scope is exited -> do you miss the garbage collector?
  • Access values via the & operator

Catching your errors

  • If a function doesn't have a Result return type, chain its call with .expect to catch panic.
  • Otherwise you can use a match statement to handle the error.
  • Errors are actually referred to as a panic :D

Stuff I barely understood

  • Use the Box API to allocate a value to the heap
  • Spawn threads with thread::spawn and join all threads with .join
  • Use Arc to ensure thread-safe resource access

Top comments (0)