LoginSignup
1
0

More than 3 years have passed since last update.

[Rust]別のスレッドで構造体のクロージャを動作させる。

Last updated at Posted at 2021-05-28

空のメモリと交換することでクロージャの所有権をthread::spawnへ渡して動作させることが出来るようにする。

元の変数は空の状態になる。

ちなみにクロージャの定義の外で拘束した値は、'staticである必要があるmoveをつけることで、所有権を移転出来る。

use std::thread;
use std::time::Duration;

//
// Option を使った方法
//

mod func {
    use std::thread;

    // 型定義
    // Sendを明示的に指定する。
    pub type FuncType = Option<Box<dyn Fn() -> Result<(), String> + Send>>;

    pub struct Func {
        pub name: String,
        pub funcs: FuncType,
    }

    impl Func {
        pub fn exec(&mut self) {
            println!("func function start.");
            // 空の変数を作る。
            let mut funcs: FuncType = None;
            // ここで後の処理で使えるようにメモリを交換
            std::mem::swap(&mut self.funcs, &mut funcs);
            thread::spawn(|| {
                match funcs {
                    Some(f) => {
                        // Fnなので複数回使える。
                        (f)();
                        (f)();
                        println!("func closure end.");
                    }
                    None => {}
                }
            });
            println!("func function end.");
        }
    }
}


fn func_main() {
    let a: String = "closure out side Variable a".to_string();
    let b: &str = "closure out side Variable b";
    let c: String = "closure out side Variable c".to_string();
    let func: func::FuncType = Some(Box::new(move || { // moveをつけることでaとcの所有権を移転
        println!("func start");
        println!(" --> {}", a);  // 所有権が移転された。
        println!(" --> {}", b);  // 参照のみなので移転しない。
        println!(" --> {}", &c); // 参照を指してもエラー。
        thread::sleep(Duration::from_millis(1000));
        println!("func end");
        Ok(())
    }));
    // println!(" > {}", a); // これはエラーになる。
    println!(" > {}", b); // これは問題ない。
    // println!(" --> {}", &c); // これはエラーになる
    let mut tmp = func::Func { name: "test".to_string(), funcs: func };
    tmp.exec();
}

//
// Vecを使った方法
//

mod funcs {
    use std::thread;

    pub type FuncsType = Vec<Box<dyn Fn() -> Result<(), String> + Send>>;

    pub struct Funcs {
        pub name: String,
        pub funcs: FuncsType,
    }

    impl Funcs {
        pub fn exec(&mut self) {
            println!("funcs function start.");
            // 空のベクトルを作る。
            let mut funcs: FuncsType = vec![];
            // ここでメモリを交換
            std::mem::swap(&mut self.funcs, &mut funcs);
            thread::spawn(|| {
                for f in funcs {
                    (f)();
                    (f)();
                    println!("funcs closure once end.");
                }
                println!("funcs closure end.");
            });
            println!("funcs function end.");
            println!("funcs function length is {}.",self.funcs.len() );
        }
    }
}

fn funcs_main() {
    let func: funcs::FuncsType = vec![Box::new(|| {
        println!("funcs start");
        thread::sleep(Duration::from_millis(1000));
        println!("funcs end");
        Ok(())
    })];
    let mut tmp = funcs::Funcs { name: "test".to_string(), funcs: func };
    tmp.exec();
}

fn main() {
    func_main();
    funcs_main();
    thread::sleep(Duration::from_millis(5000));
}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0