Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Demystifying Mutability and References in Rust
Arunanshu Biswas
Arunanshu Biswas

Posted on

     

Demystifying Mutability and References in Rust

The Un-Sandwiching rule

All references and reference related problems follow the"un-sandwiching"
rule.

The"un-sandwiching" rule states that:

Given a value, you cannot use a mutable reference between an immutable reference's declaration "zone" and immutable reference's usage "zone". Also, you cannot use mutable or immutable reference between a mutable's declaration zone and mutable's usage zone.

Note:

"Un-Sandwiching rule" is just a made up name that I created to better explain the quirks of immutable and mutable references. Don't use this name in forums!

What does it mean?

This rule is a mashed and simplified form of:

At any given time, you can have either one mutable reference or any number of immutable references. References must always be valid.

(I agree that the "un-sandwiching" rule looks more lengthy, but it will help
you to simplify things.)

Explaination of the rule

The rule can be broken down into two parts.

  1. You cannot use a mutable reference while you are between the immutable reference's declaration and usage zone. However, you may have unlimited immutable references of the same value.

  2. You cannot have any reference (immutable or mutable), if you are between a mutable reference's declaration and usage zone.

A demonstration

fnmain(){letmuta=String::from("hello world");letimmut_ref=&a;// <- declaration zone/*       This is the "un-sandwiching" zone. You can have unlimited immutable       references to `a`, directly and indirectly (more on that below), but       *NOT A SINGLE MUTABLE REFERENCE IS ALLOWED*.    */println!("{}",immut_ref);// <- usage zone}
Enter fullscreen modeExit fullscreen mode

What is allowed?

You may have these types of references between that zone (not an exhaustive list):

letb=&a;// (direct) *immutable* reference to `a`letc=&b;// (indirect) *immutable* reference to `b` (as `b` is immutable too)letd=&(*b);// (indirect) *immutable* reference to `a` via `b`
Enter fullscreen modeExit fullscreen mode

What is not allowed?

These (or any variations of these) are illegal:

letb_mut=&muta;// You can see why. It clearly violates the "un-sandwiching"// rule as we are creating a mutable reference between the// declaration and usage zone.a.push_str("breeze");// Cannot do this because `a` is an "immutable" now.// More on this below.
Enter fullscreen modeExit fullscreen mode

Let us look at thea.push_str("breeze") statement at a more granular level.

The signature ofpush_str is:

fnpush_str(&mutself,string:&str){// ...}
Enter fullscreen modeExit fullscreen mode

Can you see what's going on here?

In the signature, we have a&mut self, which basically means&mut a (sinceself isa). But going back to the "un-sandwiching" rule, we see that we cannot have amutable reference in the declaration-usage zone.

What do I mean bya becomes "immutable"?

I saya becomes "immutable" because you cannot mutatea as long as you are in the "un-sandwiching" zone. You can only have multiple immutable references.

What if we have multiple immutable references?

Let's say we have:

fnmain(){letmuta=String::from("great breeze");letb=&a;// use `b`// use some more// ...letc=&a;// use `c`// use `b`// ...letd=&c;println!("{}",b);// last usage of `b`.// use `d`// use `c`do_something(d);// last usage of `d`// use `c`// ...do_something_else(c);// last usage of `c`}
Enter fullscreen modeExit fullscreen mode

Whew! That's a lot of jumbled references! Let's see this through our declaration-usage lens.

b│││      c│      ││      │▼      │      d~b     │      │       │      │       │      │       │      ▼       │      ~d       │       │       ▼       ~c
Enter fullscreen modeExit fullscreen mode

The starting points are declarations, and the~s are the last usage of the references. Note that we don't care if a reference is a direct or an indirect one (eg.d is an indirect reference).

From this diagram, we can clearly see that the "un-sandwiching" zone ranges from the first immutable referenceb, to the last usage of immutable referencec. Betweenb and~c, you cannot have any mutable reference.

And what about moves?

letmuta=String::from("some");letc=&a;letother=a;// is this possible?println!("{}",c);
Enter fullscreen modeExit fullscreen mode

This is very simple to answer.

If the object cannot be copied, then you cannot perform a move within the zone.

Your homework

Deduce whether the following code is possible or not:

fnmain(){letmuta=String::from("mutable");letb=&muta;// a *mutable* reference// ...letc=&a;// 1. Is this possible?// ...println!("{}",b);// last usage}
Enter fullscreen modeExit fullscreen mode

And what about this?

fnmain(){letmuta=String::from("mutable");letb=&muta;// a *mutable* reference// ...letd=&muta;// 2. Is this possible?// ...println!("{}",b);// last usage}
Enter fullscreen modeExit fullscreen mode

Explaination

  1. let c = &a is not possible.

By the "un-sandwiching" rule we cannot have a immutable reference while we are within a mutable reference's "un-sandwiching" zone.

  1. let d = &mut a is not possible.

You can see why. We are trying to create a mutable reference of the value while we are within the mutable reference's "un-sandwiching" zone. This is not allowed.

Conclusion

I hope this article helps you in understanding Rust a bit better.

Questions? Comments? Concerns? Please put them down below and I'd be happy to help you.

Image Source: Manjaro's/usr/share/backgrounds folder 😃

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
seroze profile image
seroze
  • Joined

Very good explanation.

CollapseExpand
 
nick_thomas_2f14dc3861464 profile image
Nick Thomas
  • Joined

It sure did, thank you very much!

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Cryptography and Machine Learning enthusiast and paranoid about performance without sacrificing readability.
  • Joined

More fromArunanshu Biswas

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp