ソモサン

私rohkiによる活動や読書の記録をつらつらと書くページです

Rust のサンプルコードに違和感を憶えたところ

Hackathon の間に Rust をもくもくと勉強してました。
で、無意識に書いたコードとサンプルコードに差分があったので、
その辺を書いてきます。

今回の教科書はこちら
そして、件の箇所は Dining Philosophers
多分詳細を省いても伝わる内容だとおもってるので、色々略してきます。

宣言と定義

まず、無意識に書いたコードから。

use std::thread;
use std::sync::{Mutex, Arc};

struct Table {
    forks: Vec<Mutex<()>>,
}

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

で、サンプルコード。

use std::thread;
use std::sync::{Mutex, Arc};

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}

サンプルコードでは 構造体 Table の宣言の前に、関数 eat の仮引数にて table: &Table が定義されてます。
が、通る。
コンパイラの気持ちになった場合、通らなさそうなのに、通る。

悪のり開始

こうなると何処まで行けるのか試してみたくなるのが心情ってもんですよ。

構造体と関数の実装についてちょろっと試した結果、
実装を分割しても通るし、

use std::thread;
use std::sync::{Mutex, Arc};

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }
}

impl Philosopher {
    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

構造体の前に実装があっても通る。
特にこっちは通らなさそうなのに。

use std::thread;
use std::sync::{Mutex, Arc};

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }
}

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

まとめ

違和感がガガガガ(ry
僕の脳みそが古くて実際にはこんなもんだと思いたい。

ま、コード書く上では困らないので継続。