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

限于喜欢 提交于 2019-11-30 08:27:00
oli_obk

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.

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 are 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);

From the docs for std::ops::Add:

impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32

It seems the binary + operator for numbers is implemented for combinations of shared (but not mutable) references of the operands and owned versions of the operands. It has nothing to do with automatic dereferencing.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!