Comments (8)
4.1 所有権とは
これまでの一般的なプログラミング言語がメモリの管理をする場合以下の2つの方法が用いられてきた。
- 明示的に実装者がメモリの確保、開放を行う。
C言語や、C++言語 - ガベージコレクションの機構を持って、定期的に使用されていないメモリを開放する。
Javaなど
Rustは上記とは異なる、「所有権」と呼ぶ仕組みを採用することで実装者が安全にメモリを使用することができる。
from rustguide.
4.1.2 所有権規則
- Rustで用いられるメモリ上に確保された値は、所有者と呼ばれる変数と対応している。
- メモリ上に確保された値の所有者はいかなる時も一つである。
- 所有者がスコープを外れた時、確保されているメモリは解放される。
from rustguide.
4.1.3 変数スコープ
一般的な他のプログラミング言語と同じ例
文字列リテラルを使用する例(この場合はメモリはスタック上にある)
{
let s = "Hello!";
println!("{}", s); // ここはスコープ内なので有効
} // ここでスコープを外れるので s は解放される。
println!("{}", s); // ここはスコープ外なので参照できない
from rustguide.
4.1.5 メモリの確保
上記のリテラル値の場合は、コンパイル時に必要なメモリの大きさが分かっているが、実行中でないと値が決まらないようなケースの場合はString型を用いて実行時に動的にヒープメモリの確保を行う。
{
let s = String::from("Hello!");
println!("{}", s); // ここはスコープ内なので有効
} // ここでスコープを外れるので s は解放される。
println!("{}", s); // ここはスコープ外なので参照できない
String型は、drop()という関数を持っていて、Rustはスコープを外れるときに必ずこの関数を呼ぶ。
from rustguide.
4.1.5.1 変数とデータの相互作用法: ムーブ
下記のように通常のプリミティブな値の場合は、xが持つ '5'という値は
let y = x;
とする時その値もコピーされてxもyもスタックに積まれることになるため
x,y 両方とも値を参照でき、表示されスコープを外れる } の箇所で解放される
{
let x = 5;
println!("x is: {}!", x);
let y = x;
println!("y is: {}!", y); // 1
println!("x is: {}!", x); // 2
} // ここで x,y 両方とも開放
x is: 5!
y is: 5!
x is: 5!
String型を用いた場合、String::fromで確保されたメモリはヒープ上に確保されs1の実態はヒープのメモリを指すポインタのようなものでありそれがスタックに積まれる。
今までのC言語のようなメモリ管理の方法であった場合、この後に let s2 = s1
とした時は ポインタのみがコピーされ、値はヒープ上の同じ場所を指すことになる。
ここで } でスコープを外れた場合、 s1,s2ともに同じヒープ上のメモリを解放しようとして二重メモリ開放エラーを起こしてしまう。
{
let s1 = String::from("Hello");
println!("{}!", s1);
}
Rustではこの問題を、 s2 に s1 を代入したときに s1が指すヒープ上のメモリの参照を無効ににしてコンパイル時にエラーとすることで解決している。これをmove
という
{
let s1 = String::from("Hello");
println!("{}!", s1);
let s2 = s1;
println!("{}!", s2);
println!("{}!", s1);
}
error[E0382]: borrow of moved value: `s1`
--> src\main.rs:57:24
|
55 | let s2 = s1;
| -- value moved here
56 | println!("{}!", s2);
57 | println!("{}!", s1);
| ^^ value borrowed here after move```
これにより、ヒープ上のメモリを参照する変数は唯一となり二重メモリ開放が行われないことになる。
from rustguide.
4.1.5.2 変数とデータの相互作用法: クローン
ヒープ上のメモリの ディープコピーが必要な場合は, clone()
を使用する。
{
let s1 = String::from("Hello");
println!("{}!", s1);
let s2 = s1.clone();
println!("{}!", s2);
println!("{}!", s1);
}
Hello!
Hello!
Hello!
from rustguide.
4.1.6 所有権と関数
関数の引数に変数を渡すことは、別の変数に代入することと同じなので、上記で説明してきたcopy,moveの考え方に準じる。
fn main() {
{
let s = String::from("Hello!");
takes_ownership(s);
// 関数の引数に渡すことで所有権が移ってしまう。
// println!("{}", s);
let x = 5;
makes_copy(x);
// copyされるのでここでも使用できる
println!("The Value is x: {}", x);
}
}
fn takes_ownership(some_string: String) {
println!("{}", some_string);
}
fn makes_copy(number: i32) {
println!("{}", number);
}
from rustguide.
4.1.7 戻り値とスコープ
上記の例で、関数の引数に変数を渡すことで所有権の移動が起きることが分かったが
その値を呼び出し側で使えるようにするためには呼び出した関数から値を返さなければならない。
fn main() {
{
let mut s = String::from("Hello!");
s = takes_ownership(s);
println!("{}", s);
}
}
fn takes_ownership(some_string: String) -> String {
// 何かの処理
some_string
}
参照と借用
この記述を毎回行うのは大変煩わしい。
Rustにはこの概念に対する 参照 と呼ばれる機能がある。参照は変数名の頭に &
を付加することで表す。
fun main() {
let s = String::from("Hello!");
let len = reference_ownership(&s);
println!("{} length is {}", s, len);
}
fn reference_ownership(some_string: &String) -> usize {
println!("referenced {}", some_string);
some_string.len()
}
関数の引数に参照を渡すことを 借用 という。
借用した変数は、変更することはできない。つまり下記の実装は誤りであり、コンパイル時にエラーとなる。
fun main() {
let s = String::from("Hello!");
borrow_ownership(&s);
}
fn reference_ownership(some_string: &String) {
some_string.push_str(", World!");
}
参照を可変なものとするためには、以下のような記述をします。
- 変数の宣言で
mut
を付加し可変であることを宣言する。 - 関数の引数に
&mut
で宣言することで可変可能な参照であることを示す。 - 関数に変数を渡すときに
&mut
をつける。
fun main() {
let mut s = String::from("Hello!");
borrow_mutable_ownership(&mut s);
println!("{}", s);
}
fn borrow_mutable_ownership(some_string: &mut String) {
some_string.push_str(", World!");
}
可変な参照は、同一スコープ内で同時に使用できないという制限があります
from rustguide.
Related Issues (9)
- Chapter 1.1 Install HOT 2
- Chapter 1.2 Hello, world! HOT 2
- Chapter 1.3 Hello, Cargo! HOT 3
- Chapter 2.0 数当てゲームをプログラムする HOT 9
- Chapter3.1 変数と可変性 HOT 2
- Chapter 3.3 関数 HOT 2
- Chapter 3.5 フロー制御 HOT 1
- Chapter5 構造体 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rustguide.