安全性、速度、並行性を兼ね備えた言語と、巷でうわさの「Rust」を覗いてみる(その4:所有権と関数)
今回も前回に続き、「The Rust Programming Language」を読みながら、所有権と関数を覗いていきたいと思います。
ヒープを使う場合
前回で、シンプルな所有権の動きは理解できたので、関数の場合を見ていきます。
まずは、サンプルのコードを動かしてみます。
fn main() {
let s = String::from("hello");
takes_ownership(s); // hello
}
fn takes_ownership(some_string: String) {
println!("{}", some_string)
}
最初の takes_ownership 関数に s を渡すところで、sの値が関数(内のsome_string)にムーブされます。
本当にムーブされているか確かめてみます。
fn main() {
let s = String::from("hello");
takes_ownership(s);
println!("{}", s)
}
fn takes_ownership(some_string: String) {
println!("{}", some_string)
}
error[E0382]: borrow of moved value: `s`
--> src/main.rs:6:20
|
2 | let s = String::from("hello");
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
3 |
4 | takes_ownership(s); // hellp
| - value moved here
5 |
6 | println!("{}", s)
| ^ value borrowed here after move
ちゃんとエラーが出ました。
takes_ownership 関数は値を返さないので、仮引数の some_string は、この関数スコープが終了すると drop 関数がよばれて、 メモリが解放されます。スタックを使う場合
fn main() {
let x = 5;
makes_copy(x); // 5
}
fn makes_copy(some_integer: i32) {
println!("{}", some_integer)
}
先ほどと同じく、 makes_copy 関数に x を渡すところで、ムーブされるのですが、 xはスタックに保存されるデータ(Copy)なので、 some_integer に対してdrop関数が呼ばれません。
なので、 makes_copy 関数の後でもxを参照することができるらしいので試してみます。
fn main() {
let x = 5;
makes_copy(x); // 5
println!("{}", x) // 5
}
fn makes_copy(some_integer: i32) {
println!("{}", some_integer)
}
問題なく参照できました。
クロージャの場合
ちょっとイキって教科書から脱線し、クロージャの場合はどうなるのか気になったので試してみます。
fn main() {
let s = String::from("hello");
let c = |y| println!("{}", y);
c(s);
println!("{}", s);
}
error[E0382]: borrow of moved value: `s`
--> src/main.rs:8:20
|
2 | let s = String::from("hello");
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
...
6 | c(s);
| - value moved here
7 |
8 | println!("{}", s);
| ^ value borrowed here after move
関数の場合とおなじく、エラーになります。
ここまでは想定通りです。
fn main() {
let s = String::from("hello");
let c = || println!("{}", s);
c();
println!("{}", s);
}
では、 s をキャプチャした場合の所有権はどうなるのでしょうか。
こちらはエラーになりませんでした。
キャプチャした場合のsはムーブされずに、所有権は main 関数側に残ってそうです。
残念ながら、現在のRust力ではこれ以上の詳細は不明です。
正直、イキり過ぎましたね。
fn main() {
let s = String::from("hello");
let c = move || println!("{}", s);
c();
println!("{}", s);
}
すこし調べてみたところ、上記のようにクロージャの前に move を付けると、 所有権が移動してエラーになりました。
このへんの詳細は、未来の宿題ということで今はスルーしておきます。
Fn , FnMut , FnOnce のトレイトがクロージャにあり、使い分けてることをなんとなく記憶しておきます。この記事を書いた人
-
2008年にアーティスへ入社。
システムエンジニアとして、SI案件のシステム開発に携わる。
その後、事業開発部の立ち上げから自社サービスの開発、保守をメインに従事。
ドメイン駆動設計(DDD)を中心にドメインを重視しながら、保守可能なソフトウェア開発を探求している。
この執筆者の最新記事
関連記事
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー