Rust 101 – 16: Exercises for module A3 (part 1)

Going through some exercises on Rust traits, designing a customised version of Vec.

Series: 1: Intro, 2: Language basics, 3: Memory and ownership, 4: Exercises A1, 5: References, 6: Structs and Enums, 7: Panic and Result, 8: Methods, 9: Vec and Box, 10: Strings, 11: Exercises A2, 12: Traits, 13: Type Params, 14: std Traits, 15: Lifetimes, 16: Exercises A3pt1

Links:

The course materials for this series are developed by tweede golf. You can find more information at github.com/tweedegolf/101-rs and you can sponsor the work at github.com/sponsors/tweedegolf. They are released under the Creative Commons Attribution Share Alike 4.0 International license.

This series of videos is copyright 2024 Andy Balaam and the tweede golf contributors and is released under the Creative Commons Attribution Share Alike 4.0 International license.

One import per line is best

Rust has a feature where if you import two things from the same module you can abbreviate it like this:

use mypkg::{MyStruct1, MyStruct2};

If you prefer, you can keep them separate, like this:

use mypkg::MyStruct1;
use mypkg::MyStruct2;

I do prefer. Strongly.

Advantages of the abbreviated style

  • Fewer lines of code
  • Fewer characters of code

Advantages of the separated style

  • Simpler diffs with fewer conflicts. If I add or delete an import, it adds or removes exactly one line. This makes it easier to read diffs and reduces conflicts when merging.
  • Less diff noise when lines overflow. Adding or removing an import is less likely to cause the code formatter to reflow the line. Reflows make it hard to see which dependencies have changed when reading a diff.
  • Easier searching. If I’m trying to find out where a particular type is used I can search for its full path, and my search will find all the places I import it.
  • Easier to read. I find line of code like this really hard to read:
    use crate::{
        gossiping::{GossipRequest, GossippedSecret, SecretInfo},
        identities::{ReadOnlyDevice, ReadOnlyUserIdentities},
        olm::{OutboundGroupSession, PrivateCrossSigningIdentity},
        types::events::room_key_withheld::RoomKeyWithheldEvent,
        TrackedUser,
    };

I think the separated style is much better, and I wish Rustfmt defaulted to using it. What do you think?

rustfmt config

To enforce my preferred style, include this in your rustfmt.toml:

imports_granularity = Item

(Rustfmt docs)

Rust 101 – 15: Lifetime bounds

This time we tackle one of the most tricky areas for a new Rust programmer: lifetimes. The key point is that when we add lifetime bounds ('a or similar) to a function signature, this is not to help Rust compile our function: it’s to help Rust understand the lifetime of our return values, so that it knows how to compile the code that calls this function. The lifetime bounds tell the compiler about the references we return – specifically, how they relate to the references that were passed in.

Series: 1: Intro, 2: Language basics, 3: Memory and ownership, 4: Exercises A1, 5: References, 6: Structs and Enums, 7: Panic and Result, 8: Methods, 9: Vec and Box, 10: Strings, 11: Exercises A2, 12: Traits, 13: Type Params, 14: std Traits, 15: Lifetimes, 16: Exercises A3pt1

Links:

The course materials for this series are developed by tweede golf. You can find more information at github.com/tweedegolf/101-rs and you can sponsor the work at github.com/sponsors/tweedegolf. They are released under the Creative Commons Attribution Share Alike 4.0 International license.

This series of videos is copyright 2024 Andy Balaam and the tweede golf contributors and is released under the Creative Commons Attribution Share Alike 4.0 International license.

Rust 101 – 14: Some standard library traits

A tour of some of the most interesting traits in the standard library including Add etc. to overload operators, Sized, Sync and Send for telling the compiler special things about your type, Clone and Copy for copying things, Into and From for converting, AsRef and AsMut for making your APIs flexible, Default for easy creation, and Drop which is called when your object is deleted. Also a few words on what happens when you call a function with generic type parameters.

Series: 1: Intro, 2: Language basics, 3: Memory and ownership, 4: Exercises A1, 5: References, 6: Structs and Enums, 7: Panic and Result, 8: Methods, 9: Vec and Box, 10: Strings, 11: Exercises A2, 12: Traits, 13: Type Params, 14: std Traits, 15: Lifetimes, 16: Exercises A3pt1

Links:

The course materials for this series are developed by tweede golf. You can find more information at github.com/tweedegolf/101-rs and you can sponsor the work at github.com/sponsors/tweedegolf. They are released under the Creative Commons Attribution Share Alike 4.0 International license.

This series of videos is copyright 2024 Andy Balaam and the tweede golf contributors and is released under the Creative Commons Attribution Share Alike 4.0 International license.

Rust 101 – 13: Type Parameters and Associated Types

Following on from video 12, looking at how to add type information to traits, to make them flexible enough to describe generic code with different types, for example how to add a u32 to a u64 and return a u128, without defining a whole new trait for every combination of types.

Series: 1: Intro, 2: Language basics, 3: Memory and ownership, 4: Exercises A1, 5: References, 6: Structs and Enums, 7: Panic and Result, 8: Methods, 9: Vec and Box, 10: Strings, 11: Exercises A2, 12: Traits, 13: Type Params, 14: std Traits, 15: Lifetimes, 16: Exercises A3pt1

Links:

The course materials for this series are developed by tweede golf. You can find more information at github.com/tweedegolf/101-rs and you can sponsor the work at github.com/sponsors/tweedegolf. They are released under the Creative Commons Attribution Share Alike 4.0 International license.

This series of videos is copyright 2024 Andy Balaam and the tweede golf contributors and is released under the Creative Commons Attribution Share Alike 4.0 International license.