Rust 言語の入り口からピットまで - (5) Rust の所有権


ここに画像の説明を挿入

0 インポート

主にRustの所有権に関する知識を紹介しており、変数のスコープ、メモリ解放メカニズム、移動、クローン作成、参照などの知識が含まれており、Rust言語のユニークなメカニズムに関する多くの知識が含まれています。


1. 所有権

所有権には次の 3 つのルールがあります。

- Rust のすべての値には、その所有者と呼ばれる変数があります。
- 所有者は一度に 1 人だけです。
- 所有者がプログラムのスコープ内にない場合、値は削除されます。

{
    
    
    // 在声明以前,变量 s 无效
    let s = "runoob";
    // 这里是变量 s 的可用范围
}
// 变量范围已经结束,变量 s 无效

2. メモリと割り当て

ほとんどのプログラミング言語には、メモリを管理するための関数があります。

1. C/C++ などの言語は主に手動でメモリを管理しており、開発者は手動でメモリリソースの申請や解放を行う必要があります。しかし、開発効率を向上させるために、プログラムの機能実現に影響を与えない限り、メモリを適時に解放する習慣を持たない開発者が多くいます。そのため、手動でメモリを管理する方法ではリソースの無駄が発生しやすく、またメモリの解放を忘れてメモリリークが発生しやすくなります。
2. Java 言語で記述されたプログラムは仮想マシン (JVM) 上で動作し、JVM にはメモリリソースを自動的に回収する機能があります。ただし、この方法では実行時の効率が低下することが多いため、JVM はできるだけ少ないリソースを再利用することになり、プログラムが大量のメモリ リソースを占有することになります。
3. 所有権はほとんどの開発者にとって新しい概念であり、メモリを効率的に使用するために Rust 言語によって設計された構文メカニズムです。所有権の概念は、Rust がコンパイル段階でメモリ リソースの有用性をより効果的に分析してメモリ管理を実現できるようにするために生まれた概念です。
4. 所有権の設定は奇妙に思えますが、実際には同じ変数データが​​複数の変数参照を持つことは言語レベルで基本的に禁止されており、パラメーターとして渡されると所有権が移動 (Move) されます。 (借りる)。別のミューテーションに割り当てると、所有権は自動的に放棄されます。これにより、同時シナリオでのデータ共有の競合が根本的に排除されます。
5. Rust のデータ型は、基本データ型とその他の可変データ型 (String などの可変長) に分けることができます。基本データ型には、
i32
、u32、i64 などのすべての整数型、
ブール型 bool、値は true または false
すべての浮動小数点型、f32 および f64
文字型 char
上記のタイプのデータを含むタプル (タプル) のみ

基本データは通常スタック上に定義され、その他はヒープ上に定義されます。 data? 、所有権が失われるたびにRustが自動的に解放します。


3. 移動してクローンを作成する

3.1. モバイル

次のコード:

    //基本数据在栈中定义,交互数据是直接复制的,通过移动复制
    let x = 5;
    let y = x;
    println!("{}, {}",x,y);

	//其他数据在堆中交互
	let s1 = String::from("hello");
	let s2 = s1;                // 为了确保安全,在给 s2 赋值时 s1 已经无效了
	println!("{}, world!", s1); // 错误!s1 已经失效

3.2. クローン

Rustはプログラムの実行コストを可能な限り削減しようとするため、デフォルトでは長さの長いデータはヒープに格納され、データのやり取りは移動によって行われます。ただし、他の目的でデータを単にコピーする必要がある場合は、データの 2 番目の対話型方法であるクローン作成を使用できます。

    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}, s2 = {}", s1, s2);

これにより、2 つの別々のデータセットが作成されます。


4. お見積りとリース

4.1. 引用

リファレンス (Reference) は、C++ 開発者にとって馴染みのある概念です。ポインターの概念に精通している場合は、ポインターを一種のポインターとして考えることができます。本質的に、「参照」は変数への間接的なアクセス方法です。

fn main() {
    
    
    let s1 = String::from("hello");
    let s2 = &s1;
    println!("s1 is {}, s2 is {}", s1, s2);
}

1. 変数の値を参照する場合、変数自体は無効とはみなされません。「参照」はスタック内の変数の値をコピーしないため、
2. 参照は値の所有権を取得しません。参照は値の所有権を借用 (Borrow) することしかできません。参照自体も型であり、他の値の場所を記録する値を持ちますが、参照はポイントされた値の所有権を持ちません。

fn main() {
    
    
    let s1 = String::from("hello");
    let s2 = &s1;
    let s3 = s1;
    println!("{}", s2);
}
//注意 因为 s2 租借的 s1 已经将所有权移动到 s3,所以 s2 将无法继续租借使用 s1 的所有权。如果需要使用 s2 使用该值,必须重新租借,如下

fn main() {
    
    
    let s1 = String::from("hello");
    let mut s2 = &s1;
    let s3 = s1;
    s2 = &s3;        // 重新从 s3 租借所有权
    println!("{}", s2);
}

3. リースされた所有権は所有者の価値を変更することはできません、リファレンスには所有権がないため、所有権をリースしたとしても、使用する権利を享受するだけです。
4. 不変参照と比較すると、可変参照では複数の参照が許可されませんが、不変参照では許可されます。

fn main() {
    
    
    let s1 = String::from("run");
    let s2 = &s1;
    println!("{}", s2);
    s2.push_str("oob"); // 错误,禁止修改租借的值
    println!("{}", s2);
}
//当然加上 mut表示可变变量时候,是允许修改的
fn main() {
    
    
    let mut s1 = String::from("run");
    // s1 是可变的

    let s2 = &mut s1;
    // s2 是可变的引用

    s2.push_str("oob");
    println!("{}", s2);
}

4.1. ぶら下がり参照

C++ では、これは次のとおりです。 ポインタの概念を持つプログラミング言語では、アクセス可能なデータを実際には指さないポインタを指します (必ずしもヌル ポインタである必要はなく、解放されたリソースである場合もあることに注意してください) ) 、これは Rust では許可されません。
通常、ローカル変数は関数内で定義され、関数の戻り値は参照になります。これは、ローカル変数参照が返される場合です。

5. 関数内の変数

5.1 パラメータ変数

関数内の変数解放の仕組みは上で紹介したものと同じですが、以下の点に注意してください。

fn main() {
    
    
    let s = String::from("hello"); // s 被声明有效
    takes_ownership(s); // s 的值被当作参数传入函数, 所以可以当作 s 已经被移动,从这里开始已经无效
    let x = 5;          // x 被声明有效
    makes_copy(x);      // x 的值被当作参数传入函数
                        // 但 x 是基本类型,依然有效
                        // 在这里依然可以使用 x 却不能使用 s
} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放

fn takes_ownership(some_string: String) {
    
     // 一个 String 参数 some_string 传入,有效
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    
    // 一个 i32 参数 some_integer 传入,有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放

5.2、戻り値変数

関数の戻り値として使用される変数の所有権は、直接無効化されるのではなく、関数の外に移動され、関数が呼び出された場所に戻されます。

fn main() {
    
    
    let s1 = gives_ownership(); // gives_ownership 移动它的返回值到 s1
    let s2 = String::from("hello"); // s2 被声明有效
    let s3 = takes_and_gives_back(s2);// s2 被当作参数移动, s3 获得返回值所有权
} // s3 无效被释放, s2 被移动, s1 无效被释放.
fn gives_ownership() -> String {
    
    
    let some_string = String::from("hello"); // some_string 被声明有效
    return some_string; // some_string 被当作返回值移动出函数
}
fn takes_and_gives_back(a_string: String) -> String {
    
     
    // a_string 被声明有效
    a_string  // a_string 被当作返回值移出函数
}

おすすめ

転載: blog.csdn.net/ljsant/article/details/131349775