Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of the ampersand '&' and star '*' symbols in Rust

Despite thoroughly reading the documentation, I'm rather confused about the meaning of the & and * symbol in Rust, and more generally about what is a Rust reference exactly.

In this example, it seems to be similar to a C++ reference (that is, an address that is automatically dereferenced when used):

fn main() {     let c: i32 = 5;     let rc = &c;     let next = rc + 1;     println!("{}", next); // 6 } 

However, the following code works exactly the same:

fn main() {     let c: i32 = 5;     let rc = &c;     let next = *rc + 1;     println!("{}", next); // 6 } 

Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.

My understanding so far, is that, inserting * in front of a Rust reference dereferences it, but the * is implicitly inserted anyway so you don't need to add it (while in C++, it's implicitly inserted and if you insert it you get a compilation error).

However, something like this doesn't compile:

fn main() {     let mut c: i32 = 5;     let mut next: i32 = 0;     {         let rc = &mut c;         next = rc + 1;     }     println!("{}", next); } 
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`  --> src/main.rs:6:16   | 6 |         next = rc + 1;   |                ^^^^^^   |   = note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work   = note: an implementation of `std::ops::Add` might be missing for `&mut i32` 

But this works:

fn main() {     let mut c: i32 = 5;     let mut next: i32 = 0;     {         let rc = &mut c;         next = *rc + 1;     }     println!("{}", next);  // 6 } 

It seems that implicit dereferencing (a la C++) is correct for immutable references, but not for mutable references. Why is this?

like image 676
John Smith Optional Avatar asked Mar 31 '16 13:03

John Smith Optional


People also ask

What does the ampersand symbolize?

An ampersand is a sign for the word and. It's written or typed as the symbol &. It's a modification of the term “and per se and,” which has Latin origins. The ampersand can indicate that the listed items are grouped together as part of a name.

What is this called symbol &?

What is an &? & is called an ampersand symbol (pronounced “AM- per-sand”). Essentially, it means “and”. It is used both (a) in the body of the paper as part of a citation and (b) at the end of the paper as part of a reference.

What is the history of the ampersand?

The origin of the ampersand can be traced back to the Latin word et, meaning 'and'. The E and the T that make up this word were occasionally written together to form a ligature (a character consisting of two or more joined letters).

What does the & symbol mean tattoo?

Ampersand Tattoo The ampersand symbol, also commonly referred to as the “and” symbol, is a simplistic design that can signify a great many things. Traditionally the ampersand tattoo meaning can be interpreted as representing union, togetherness, marriage, friendship, or an attachment to a person, place or concept.


2 Answers

Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.

A reference in C++ is not the same as a reference in Rust. Rust's references are much closer (in usage, not in semantics) to C++'s pointers. With respect to memory representation, Rust's references often are just a single pointer, while C++'s references are supposed to be alternative names of the same object (and thus have no memory representation).

The difference between C++ pointers and Rust references is that Rust's references are never NULL, never uninitialized and never dangling.


The Add trait is implemented (see the bottom of the doc page) for the following pairs and all other numeric primitives:

  • &i32 + i32
  • i32 + &i32
  • &i32 + &i32

This is just a convenience thing the std-lib developers implemented. The compiler can figure out that a &mut i32 can be used wherever a &i32 can be used, but that doesn't work (yet?) for generics, so the std-lib developers would need to also implement the Add traits for the following combinations (and those for all primitives):

  • &mut i32 + i32
  • i32 + &mut i32
  • &mut i32 + &mut i32
  • &mut i32 + &i32
  • &i32 + &mut i32

As you can see that can get quite out of hand. I'm sure that will go away in the future. Until then, note that it's rather rare to end up with a &mut i32 and trying to use it in a mathematical expression.

like image 196
oli_obk Avatar answered Sep 19 '22 10:09

oli_obk


This answer is for those looking for the basics (e.g. coming from Google).

From the Rust book's References and Borrowing:

fn main() {     let s1 = String::from("hello");      let len = calculate_length(&s1);      println!("The length of '{}' is {}.", s1, len); }  fn calculate_length(s: &String) -> usize {     s.len() } 

These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].

The opposite of referencing by using & is dereferencing, which is accomplished with the dereference operator, *.

And a basic example:

let x = 5; let y = &x; //set y to a reference to x  assert_eq!(5, x); assert_eq!(5, *y); // dereference y 

If we tried to write assert_eq!(5, y); instead, we would get a compilation error can't compare `{integer}` with `&{integer}`.

(You can read more in the Smart Pointers chapter.)

And from Method Syntax:

Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.

Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:

p1.distance(&p2); (&p1).distance(&p2); 
like image 45
mb21 Avatar answered Sep 19 '22 10:09

mb21