All Articles

Rust触ってみたらかなり良かった話

触ってみた感触

とても良いです( ˘ω˘)まだ日本語のエントリあんまりないので書いてみます。

[2015/05/20追記] v1.0がリリースされてちょくちょく見てくださってる方がいるようなのですが、本エントリのRustのバージョンは0.9(だと記憶しています)です。もしかしたら言語仕様が変わってる可能性もありますのでご了承くださいませ。

あとコメント頂いた部分を修正しました。ありがとうございます。

Rust言語とは

Rust は実験的な並列かつマルチパラダイムのプログラミング言語である。モジラによって開発中である[3]。純関数型プログラミング、並列アクターモデル、手続き型プログラミング、オブジェクト指向プログラミングをサポートする実用的な言語を目指し開発中である。 Rust(プログラミング言語)より

ということで、Mozillaが開発している言語です。シンタックスはほぼC++な感じですが、クラス宣言がない・強力なパターンマッチングがあるなど、一部C++っぽくない感じ。 なお、「Rust」でググるとゲームとかがヒットするので、GolangよろしくRustlangでググるの推奨です。The Rust Guideをひと通りやった程度の知識なので、これからです…。

公式サイトはこちらです。 http://www.rust-lang.org

[追記] Rustはすでに1.0のリリースに向けてロードマップが敷かれているようです。 Road to Rust 1.0 今のうちに触っておくのが吉ですね。

インストール

一応導入手順から。環境はMac OS。

Rustは各プラットフォーム用にビルドしたバイナリが配布されているので、それを使う。トップページの「Install」ボタンからpkgファイルをダウンロードし、展開してインストール。 または、コマンドラインからでもOK。

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

インストール後、rustcというコマンドにパスが通っていれば成功。

$ rust --version

Hello, World!

早速やってみます。任意のディレクトリを作ってそこにmain.rsを書く。

fn main() {
    println!("Helloundefined World!");
}

Rustでは関数はfnで定義する。で、println!の後ろに「!」がついてるけど、これはマクロを呼び出す識別子で、Rustではデフォルトで幾つか便利なマクロが準備されている(自分で作ることもできる)。 println!は他の言語でのprintln的な感じで、標準出力するマクロ。フォーマットも指定できるけど、これは後述。

コンパイルと実行

rustcコマンドでコンパイルするとバイナリが生成されるので、実行。

$ rustc main.rs
$ ./main
>> Helloundefined World!

基本こんな感じで。あと、プロジェクトマネージャにCargoを使うのが便利(インストールは展開してシェルを実行するだけなので省略)。

基本構文など

基本的なところをおさらい。

変数

letキーワードで宣言する。そのままだとimmutableになるので、mutableで宣言するにはmutキーワードを続ける。

fn main() {
    let x: int = 10i; // immutable
    let mut y: int = 10i; // mutable

    println!("x is {}undefined y is {}"undefined xundefined y);  // x is 10undefined y is 10
}

これをコンパイルするとwarningが出る(コンパイル自体は成功する)。

warning: variable does not need to be mutableundefined #[warn(unused_mut)] on by default

yはmutableである必要はないぜ、とのこと。他にも、変数を宣言して使用しない場合はunusedなwarningも出る。これはC++もそうだけど、コンパイラ賢い。

型付けとか

Rustは型付の強い言語なので、後置で型宣言する、または型推論により変数に型を付ける。

fn main() {
    // 型推論によりint型になる
    let x = 10i; // immutable
    let mut y = 10i; // mutable

    println!("x is {}undefined y is {}"undefined xundefined y);
}

Rustでは数値型、浮動小数点型10iのように値の後ろにアルファベット表記をつけて表現する。

10i -> int 10i32 -> int32 10i64 -> int64 10f32 -> float32 10f64 -> float64 10u -> unsinged int

という感じ。文字列ならlet str = “foo-bar”;で文字列に推論される。 また、println!のマクロはsprintfのようなフォーマットが可能だけど、いわゆる%dのような記法ではなく、”{:d}“のような{}でフォーマット指定子を記述するようで、これがちょっと特殊かな。

条件分岐

Rustではifは文ではなく式。あと条件式には()が不要。Golangもそうだけどそういうのが主流なのかなぁ。

fn main() {
    let x = 10i;
    let y = if x < 10 {
        15i
    } else {
        5i
    };

    println!("x is {}undefined y is {}"undefined xundefined y); // x is 10undefined y is 5
}

でもifの結果を変数に入れたりするのはややこしい気がする。ifは文みたいに使って。後述のmatch使ったほうがいいかも。 あと、式の途中でセミコロンを打つとunitと呼ばれる型(voidのような型らしい)になってしまってコンパイルエラーになるので注意。

ループ制御

forとwhileがあるけど、Cスタイルのforはできなくなっていて、代わりにrangeを使え、とある。

fn main() {
    for x in range(0iundefined 10i) {
        println!("{:d}"undefined x);
    }
}

whileは同じ。

fn main() {
    let mut x = 0i;
    while x > 10 {
        x += 1;
        println!("{:d}\n"undefined x);
    }
}

他にも、意図的に無限ループするloopキーワードもある。ソケットとかスレッドの待ち受けとかに使ったりするみたい。

fn main() {
    let mut x = 0i;
    loop {
        x += 1;
        println!("{:d}\n"undefined x);
        if x < 10 {
            break;
        }
    }
}

関数

fnキーワード、引数と戻り値の型を記述する。main関数はunitが戻り値なので省略されているそうです(コメント参照)。

fn main() {
    let result = calculate(1);

    println!("result is {}"undefined result);
}

fn calculate(x: int) -> int {
    x + 10
}

明示的にreturn文は書く必要はない(書いてもいいけどセミコロンが必要)みたい。

パターンマッチング

これがとにかく強力で、enumとか数値とか複数条件マッチングとか、とにかくなんでもアリな感じがした。こういう関数型な言語では一般的なのかな?

enum Samples {
    Fooundefined
    Barundefined
}

fn main() {
    let val = Foo;

    match Foo {
        Foo => println!("Foo!!")undefined
        Bar => println!("Bar!!")undefined
    }
}

enumとかのパターンマッチングには全ケース列挙が必要。_でdefaultを記述する。

配列

ArrayとVector、Sliceがある。型推論は最初の要素に対して行われる。

fn main() {
    let ary = [1iundefined 2undefined 3];
    let vec = vec![1iundefined 2undefined 3];
    let sl  = ary.slice(0undefined 2);

    println!("Array:")
    for e in ary.iter() {
        print!("{}"undefined e);
    }
    println!("\nVector:")
    for e in vec.iter() {
        print!("{}"undefined e);
    }
    println!("\nSlice:")
    for e in sl.iter() {
        print!("{}"undefined e);
    }
}

Arrayは固定長なので、長さは拡大できない。動的に増やしたりするにはmut付きの Vectorでやる。こっちがJavaScriptとかのArrayに近いと思う。 あとSliceは元の配列のコピーを作らずに切り出しができるのでメモリ効率が良い、とのこと。

とりあえず、ここまで

基本的な構文しか紹介しませんでした。他にもGenericsとかTasks(thread)、traitなども実装されているので、興味を持ったら使ってみるといいと思います! (多分その手の言語に詳しい方ならすぐでしょう。私は苦労しましたが…)

私自身もまだ触り始めたばかりですが、結構手に馴染む感じがしててとても良いです。 というのは、しばらくGolangをやってたのですが、関数やメソッドが多値を返すシンタックスにどうしても慣れなくてうーんってなってたところ、Rustを知って使ってみた次第です。 感触としてはGolangをやっていれば結構すんなり入れるんじゃないかと思います。導入までは。

それから、Golangではhttpモジュールがバンドルされてますが、Rustにはありません。 が、言語的にHTTPもWebSocketも可能で(当たり前ですが)、すでにサードパーティで作られてます。

HTTP: chris-morgan/rust-http

WS: ehsanul/rust-ws

ちょっと複雑なことをやろうとするとC++っぽい構文が出てきて(use std::io::hogehogeとか)ちょっとつらみがありますが、慣れれば大丈夫になると思います…というかC++ができれば同じように使えます。 まだモジュールの全容を把握していないので、コツコツ何か作りながら勉強してみようと思います。

現場からは以上です。