Rustを触ってみる


Rustとは
* Type safety
* Memory safety
* Concurrency and performance

にフォーカスした言語とのこと。なるほどちょっと面白そうね、ということで触ってみます。

Rustのインストール
-

```bash
curl -s https://static.rust-lang.org/rustup.sh | sudo sh
```

結構ダウンロードまでかかる・・・

自動でRustとその上のパッケージ管理システムであるCargoも入るみたいです。

```bash
mypc:examples shot$ rustc --version
rustc 0.13.0-nightly (ffc111889 2014-12-12 21:07:19 +0000)

mypc:examples shot$ cargo --version
cargo 0.0.1-pre-nightly (0f6667c 2014-12-08 21:19:01 +0000)
```

Cargoはここみると早そう。
http://doc.crates.io/guide.html


Hello World
-

下記サイトで色々サンプルがあって、まずはここを写経。
http://rustbyexample.com/


コードも全部公開しているので、ひとまずclone.

```
git clone https://github.com/rust-lang/rust-by-example.git
```

まずはHello World. fnがファンクション(macroと呼ぶみたい)のようですねー。ファンクションの呼び出しは!を使うようです。

```rust
// This is the main function
fn main() {
    // The statements here will be executed when the compiled binary is called

    // Print text to the console
    println!("Hello Rust!");
}
```


実行バイナリはrustcでコンパイルして生成するようです。やってみましょう。

```bash
mypc:hello shot$ rustc hello.rs 
mypc:hello shot$ ./hello 
Hello Rust!
```

Formatted Print
-

次はprint系マクロで整形しながら出力してみます。

```rust
fn main() {
    // 普通のprintの呼び出し
    print!("January has ");

    // {}でプレースホルダーが使える。型の話は次で。iはintegerぽい
    println!("{} days", 31i);

    println!("-----------------")
 
    // {0}, {1}のような数値つきプレースホルダーも使える
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // 名前付きはわかりやすくて、嬉しい
    println!("{subject} {verb} {predicate}",
             predicate="over the lazy dog",
             subject="the quick brown fox",
             verb="jumps");

    // `:`で特殊フォーマットみたいだけど、今の所よくわかってない
    println!("{} of {:b} people know binary, the other half don't", 1i, 2i);

    // プレースホルダーと引数の数があってないとエラーになる
    println!("My name is {0}, {1} {0}", "Bond");
}
```


rustcでコンパイルエラーを出すと、きちんとしたエラーが出ますね。うん、わかりやすい。

```bash
mypc:print shot$ rustc print.rs 
print.rs:25:14: 25:39 error: invalid reference to argument `1` (there is 1 argument)
print.rs:25     println!("My name is {0}, {1} {0}", "Bond");
                         ^~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
```

というわけでエラーの出るコードをなおして、実行。

```bash
mypc:print shot$ rustc print.rs 
mypc:print shot$ 
mypc:print shot$ ./print 
January has 31 days
-----------------
Alice, this is Bob. Bob, this is Alice
the quick brown fox jumps over the lazy dog
1 of 10 people know binary, the other half don't
My name is Bond, James Bond
```


Literals and Operators
-

次はリテラルと演算子。

```rust
fn main() {
    // 普通の足し算
    println!("1 + 2 = {}", 1u + 2);

    // 型をきちんとあわせないと結果が、という例
    println!("1i - 2 = {}", 1i - 2);
    println!("1u - 2 = {}", 1u - 2);

    // &&, ||, !などのブーリアンオペレーターが使える
    println!("true AND false is {}", (true && false));
    println!("true OR false is {}", true || false);
    println!("NOT true is {}", !true);

    // ビット演算
    println!("0011 AND 0101 is {:04b}", 0b0011u & 0b0101);
    println!("0011 OR 0101 is {:04b}", 0b0011u | 0b0101);
    println!("0011 XOR 0101 is {:04b}", 0b0011u ^ 0b0101);
    println!("1 << 5 is {}", 1u << 5);
    println!("0x80 >> 2 is 0x{:x}", 0x80u >> 2);

    // アンスコでリーダビリティあがると言ってるけど、ちょっと微妙かな・・・
    println!("One million(1_000_000) is written as {}", 1_000_000u);
}
```

まあ一般的な演算子が使えそうです。


Variables
-

ちょっとコードをなおして、変数渡しだけではなく、もう一度代入してみた(letってきてるのでアトミックで出来ない想定)。

```rust
fn main() {
    //letで変数を定義
    let an_integer = 1u;
    let a_boolean = true;
    let unit = ();

    // 変数のコピー
    let copied_integer = an_integer;

    println!("An integer: {}", copied_integer);
    println!("A boolean: {}", a_boolean);
    println!("Meet the unit value: {}", unit);

    an_integer = 123u;
    println!("An integer: {}", copied_integer);

    // コンパイラーが利用していない変数は警告。アンスコつけると、警告しないみたい
    let _unused_variable = 3u;
    let noisy_unused_variable = 2u;
}
```


コンパイルしてみると、出来ない。エラーも丁寧な印象で、再アサインした所と元の設定のところの2つが出る。実用レベルはまだわかんないけど、良い感じです。


```bash
mypc:variables shot$ rustc variables.rs 
variables.rs:14:2: 14:19 error: re-assignment of immutable variable `an_integer`
variables.rs:14 	an_integer = 123u;
                	^~~~~~~~~~~~~~~~~
variables.rs:3:9: 3:19 note: prior assignment occurs here
variables.rs:3     let an_integer = 1u;
                       ^~~~~~~~~~
error: aborting due to previous error
```

というわけでコードで再アサインしているところを取り除いてコンパイル・実行。unusedな変数もきっちり捕捉されていてよい感じです。_で始めた変数はひっかからないみたい。

```bash
5cf93891c702:variables ohtani$ rustc variables.rs 
variables.rs:16:9: 16:30 warning: unused variable: `noisy_unused_variable`, #[warn(unused_variables)] on by default
variables.rs:16     let noisy_unused_variable = 2u;
                        ^~~~~~~~~~~~~~~~~~~~~
```

というわけで基本は変数はletで定義して、イミュータブルであることがわかりました。というわけで、変更可能な変数はmutで定義するようです。

```rust
fn main() {
    //変更不可能
    let _immutable_variable = 1i;
    //mut定義で変数を変更可能に出来る
    let mut mutable_variable = 1i;

    println!("Before mutation: {}", mutable_variable);

    // 変更
    mutable_variable += 1;

    println!("After mutation: {}", mutable_variable);

    // もちろんlet定義だけの変数は変更不可能
    //_immutable_variable += 1;
}

```


```bash
mypc:mut shot$ rustc mut.rs 
mypc:mut shot$ ./mut 
Before mutation: 1
After mutation: 2```
```

スコープと変数宣言のところはなんか当たり前だったので、省略で。
* スコープが異なる変数は使えない
* 変数の初期化する前には変数は使えない

くらいかなあ。変数は宣言時にもう利用する状態にしとけってことで。


Types
-

型はRustで決められたものの他に自分でエイリアスのように作る事も出来るけど、新しい型が作られる訳じゃなさそう。基本的には明示的なキャストを<b>as xxx</b>で実施するみたい。型を初期で決めないようにも定義できるみたいだけど、あとで決定できる要素（つまり値の代入）が無い場合には、コンパイルエラーになるみたい。Inferenceって言うみたいっす。


```rust
// `NanoSecond` is a new name for `u64`
type NanoSecond = u64;
type Inch = u64;

// Use an attribute to silence warning
#[allow(non_camel_case_types)]
type uint64_t = u64;
// TODO ^ Try removing the attribute

fn main(){
    // タイプ側にアノテーションがついている場合
    let a_float: f64 = 1.0;

    // 値側にタイプをつける
    let mut an_integer = 5i;

    // mutのついた変数でも型を変更する事は出来ない
    // an_integer = true;

    println!("{}", a_float);
    println!("{}",an_integer);

    let decimal = 65.4321_f32;

    // 暗黙的なキャストは許可されない
    // let integer: u8 = decimal;

    // 明示的なキャスト
    let integer = decimal as u8;
    let character = integer as char;

    println!("Casting: {} -> {} -> {}", decimal, integer, character);


        // エイリアス 
    // `NanoSecond` = `Inch` = `uint64_t` = `u64`
    let nanoseconds: NanoSecond = 5 as uint64_t;
    let inches: Inch = 2 as uint64_t;

    println!("{} nanoseconds + {} inches = {} unit?",
             nanoseconds,
             inches,
             nanoseconds + inches);

        let xx = 1u8;
        let yy = 2u;
        let zz = 3f32;
        let i = 1;
        let f = 1.0;
    println!("size of `x` in bytes: {}", std::mem::size_of_val(&xx));
    println!("size of `y` in bytes: {}", std::mem::size_of_val(&yy));
    println!("size of `z` in bytes: {}", std::mem::size_of_val(&zz));
    println!("size of `i` in bytes: {}", std::mem::size_of_val(&i));
    
    //これをコメントアウトすると、i, fが型が決まらないため、エラー
    let _constraint_i = xx + i;
    let _constraint_f = zz + f;

}

```

```bash
mypc:type shot$ rustc type.rs 
type.rs:48:6: 48:11 error: cannot determine a type for this local variable: cannot determine the type of this integer; add a suffix to specify the type explicitly [E0102]
type.rs:48 	let i = 1;
           	    ^~~~~
error: aborting due to previous error
```


Expression
-

Rustではほぼ全部がエクスプレッションなので、値を返す事になっています。なので、式として書いても最後には値を返す事になるのですが、返したくない場合は最後をセミコロンで終えると()を返すみたい。うう、これはまりそうだな・・・

Expressionは値を返すもので、Statementは値を返さないものという区分けのようだ。letがStatementで他はExpressionであると。この概念は大事だな(正確にはDeclaritive statement vs Expression statement)。

ちょっとコードで。

```rust
fn main(){
        let x = 5u;

        //最後の行がyに割当
        let y = {
                let xx = x * x;
                let xxx = xx * x;
                xxx + xx + x
        };

        //;をつけると、サプレスされて()が割当
        let z = {
                2 * x;
        };
        println!("x is {}", x);
        println!("y is {}", y);
        println!("z is {}", z);

        let n2 = if n == 5i { n * n } else { n };
        //let n2:int = if n == 5i { n * n; } else { n; };
        println!("{}", n2); 

}
```

先ほどのセミコロンの話にもどってくるけど、仮に上のコードで
```rust
let n2:int = if n == 5i { n * n; } else { n; };
```

をコメントアウトをとって使おうとすると、アノテーションとしてはintを期待しているのに、ifクローズの中でセミコロンがあるため、サプレスされて()が返る。Rustの中で、()はunitと呼ばれ、特殊な型であるみたい。というわけで下記のようなコンパイルエラーになる。


```bash
mypc:expression shot$ rustc expr.rs 
expr.rs:40:15: 40:48 error: mismatched types: expected `int`, found `()` (expected int, found ())
expr.rs:40 	let n2:int = if n == 5i { n * n; } else { n; };
           	             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
```

うーん、このケースの使いどころはまだわかっていない・・・


ここまでのまとめ
-

Rustをここまで触ってみて、なかなかシンプルでType safetyもある言語だということはわかった。もうちょっと触ってみないと真価はわからないかもだけど。長くなってきたのでこの辺で切ってみる。