Skip to content

Instantly share code, notes, and snippets.

@YusukeHosonuma
Created May 6, 2018 14:20
Show Gist options
  • Save YusukeHosonuma/13a63792d14cc68244eaa1e25f479262 to your computer and use it in GitHub Desktop.
Save YusukeHosonuma/13a63792d14cc68244eaa1e25f479262 to your computer and use it in GitHub Desktop.
FnOnce / Fn / FnMut の違いと thread::spawn およびループとの関係
use std::thread;
fn main() {
//
// FnOnce(所有権をムーブ)
//
let s = String::from("FnOnce");
execute_fn_once(move |suffix| { // 今回は`execute`のシグネチャから`FnOnce`であると推論できるので`move`は省略可能
println!("{}{}", s, suffix); // => FnOnce!
});
// 所有権ムーブ後なので以下はコンパイルエラー
//println!("s: {}", s);
//
// Fn(借用)
//
let s = String::from("Fn");
execute_fn(|suffix|{
println!("{}{}", s, suffix); // => Fn!
});
// 所有権はムーブしてないので以下はOK
println!("s: {}", s); // => s: Fn
//
// FnMut(mut借用)
//
let mut s = String::from("FnMut");
execute_fn_mut(|suffix|{
s.push_str("**");
println!("{}{}", s, suffix); // => FnMut**!
});
// 所有権はムーブしてないので以下はOK(クロージャ内の処理によって文字列は変更されている)
println!("s: {}", s); // => s: FnMut**
//
// thread::spawn で `FnOnce` を利用する
//
{
let s = String::from("FnOnce");
thread::spawn(move || {
// `s`の所有権がクロージャに移るのでこれは問題なし
println!("s: {}", s);
});
// 所有権ムーブ後なので当然コンパイルエラー
// println!("s: {}", s);
//
// 複数のスレッドを立ち上げようとする(コンパイルエラー)
//
let s = String::from("FnOnce");
for _ in 0..4 {
thread::spawn(move || {
// 1回目のループで所有権を奪うので、2回目のループでは所有権ムーブ後なのでコンパイルエラーとなる
// という感じで Rust コンパイラはループにおける所有権もトラッキングする
println!("s: {}", s);
});
}
}
//
// thread::spawn で `Fn` を利用しようとする(コンパイルエラー)
//
{
let s = String::from("Fn");
thread::spawn(|| {
// `s`を借用しようとしているが、所有者より長く生き残る可能性があるのでコンパイルエラー
// C++で考えるならコンパイルは通るものの実行時にダングリングポインタを参照する可能性がある。
println!("s: {}", s);
});
// `s`はここで解放される
}
// `FnMut`も同様の理由でコンパイルできない
// 付け加えるなら所有権システム的にも、Read/Write が同時に行われる可能性があるのでNG
}
//
// FnOnce(所有権をムーブ)
//
fn execute_fn_once<F>(f: F) where F: FnOnce(String) {
f(String::from("!"));
}
//
// Fn(借用)
//
fn execute_fn<F>(f: F) where F: Fn(String) {
f(String::from("!"));
}
//
// FnMut(mut借用)
//
fn execute_fn_mut<F>(mut f: F) where F: FnMut(String) { // `f`も`mut`にする必要がある
f(String::from("!"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment