web-dev-qa-db-ja.com

Rust)のアンパサンド '&'およびスター '*'記号の意味

ドキュメントをよく読んだにもかかわらず、Rustの&および*記号の意味について、より一般的にはRust参照)とは何かについて、私はかなり混乱しています。 。

この例では、C++参照(つまり、使用時に自動的に逆参照されるアドレス)に似ているようです。

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

ただし、次のコードはまったく同じように機能します。

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

*を使用して参照を逆参照することは、C++では正しくありません。だから私はこれがRustで正しい理由を理解したいと思います。

これまでの私の理解では、Rust参照の前に*を挿入すると逆参照されますが、*はとにかく暗黙的に挿入されるため、必要はありません。追加します(C++では、暗黙的に挿入され、挿入するとコンパイルエラーが発生します)。

ただし、このようなものはコンパイルされません。

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`

しかし、これは機能します:

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

暗黙の逆参照(C++)は不変の参照には正しいようですが、可変の参照には正しくないようです。どうしてこれなの?

19

*を使用して参照を逆参照することは、C++では正しくありません。だから私はこれがRustで正しい理由を理解したいと思います。

C++での参照は、Rustでの参照と同じではありません。 Rustの参照は、C++のポインターにはるかに近い(セマンティクスではなく使用法で)。メモリ表現に関しては、Rustの参照は多くの場合、単一のポインタですが、C++の参照は同じオブジェクトの代替名であると想定されています(したがって、メモリ表現はありません)。

C++ポインタとRust参照)の違いは、Rustの参照がNULLになることはなく、初期化されておらず、ぶら下がっていないことです。


Add トレイトは、次のペアと他のすべての数値プリミティブに対して実装されます(ドキュメントページの下部を参照)。

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

これは、std-lib開発者が実装した便利なものです。コンパイラーは、&mut i32が使用できる場所ならどこでも&i32を使用できることを理解できますが、ジェネリックスでは(まだ?)機能しないため、std-lib開発者も実装する必要があります。次の組み合わせ(およびすべてのプリミティブの組み合わせ)のAdd特性:

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

ご覧のとおり、それはかなり手に負えなくなる可能性があります。将来的にはなくなると確信しています。それまでは、&mut i32で終わり、数式で使用しようとすることはめったにないことに注意してください。

21
oli_obk

この答えは、基本を探している人のためのものです(例えば、Googleから来ています)。

Rust本の 参照と借用 から:

_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()
}
_

これらのアンパサンドは参照であり、所有権を取得せずに何らかの値を参照できるようにします[つまり、借りる]。

_&_を使用して参照するのとは逆に、dereferencingがあります。これは、逆参照演算子_*_を使用して実行されます。

そして基本的な例:

_let x = 5;
let y = &x; //set y to a reference to x

assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
_

代わりにassert_eq!(5, y);を書き込もうとすると、コンパイルエラー_can't compare `{integer}` with `&{integer}`_が発生します。

(詳細については、 スマートポインタの章 を参照してください。)

そして メソッド構文 から:

Rustには、自動参照および逆参照と呼ばれる機能があります。メソッドの呼び出しは、この動作をするRustの数少ない場所の1つです。

仕組みは次のとおりです。object.something()を使用してメソッドを呼び出すと、Rustは自動的に_&_、_&mut_、または_*_を追加します。したがって、オブジェクトはメソッドのシグネチャと一致します。つまり、以下は同じです。

_p1.distance(&p2);
(&p1).distance(&p2);
_
8
mb21

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

数値の二項+演算子は、オペランドの共有(ただし可変ではない)参照とオペランドの所有バージョンの組み合わせに対して実装されているようです。自動逆参照とは何の関係もありません。

3
Jascha