Closed4
Rustの所有権についてまとめる
まずは基本的な所
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
※ 動かない
としたときRustではshallow copyすらされずにムーブが起きる
他の言語だとヒープに存在する実態とスタックに存在するポインタやlength、capacityがコピーされる(shallow copy)
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
とすればヒープ上のデータもコピーされる(deep copy)
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
は動く。整数などのスタック上に保持される値に関してはshallow copyしか起こり得ないので暗黙的なコピーが認められている。
- 整数
- 浮動小数
- bool
- 上記のみの型で構成されるタプル (i32, i32)はCopy、(i32, String)は違う
は暗黙的にコピーされる
fn main() {
let s = String::from("hello"); // sがスコープに入る
takes_ownership(s); // sの値が関数にムーブされる
// ... ここではもう有効ではない
}
fn takes_ownership(some_string: String) { // some_stringがスコープに入る。
println!("{}", some_string);
} // ここでsome_stringがスコープを抜け、`drop`が呼ばれる。メモリが解放される。
関数に渡す際もmoveが発生する。なのでtakes_ownership関数の後にsを利用しようとするとコンパイルエラーになる。
値を返せば解決出来る。
fn main() {
let s1 = String::from("hello");
let s2 = takes_and_gives_back(s1); // s1はtakes_and_gives_backにムーブされ
// 戻り値もs2にムーブされる
}
fn takes_and_gives_back(a_string: String) -> String { // a_stringがスコープに入る。
a_string // a_stringが返され、呼び出し元関数にムーブされる
}
ただし、毎回返していては大変なので参照を利用する手もある。
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()
}
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
rustにおいて単純な参照は不変なので上記のコードは動かない。
可変にしたければmutを付ける。
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
変数のスコープを超えて参照は返せない。これはコンパイルエラーになる。
このあたりはライフタイムも絡むので別途まとめる
このスクラップは2024/12/29にクローズされました