読者です 読者をやめる 読者になる 読者になる

rust の lifetime

まずは 1.0 alpha リリースおめでとうございます。

リリースしてドキュメント関係が差し替わって Book (旧 guide) に lifetime について乗るようになったぽい。

C++ はリファレンスによって NULL ポインタのデリファレンスを防げるようになったが、ダングリングリファレンスは依然として起こってしまう。 rust の lifetime の概念はこれを解決するためのものらしい。

lifetime は Book にあるように、 場合によって省略可能だが、コンパイラが決定できない場合ユーザーが明示的に指定する必要がある。 具体的には、以下のような場合。

fn f<'a> (x: &'a i32, y: &i32) -> &'a i32 {
    x
}

fn main() {
    let x = 1;
    let r: &i32;
    {
        let y = 2;
        r = f(&x, &y);
    }
}

この場合、f の仮引数の x と戻り値の lifetime が同一であると 'a として lifetime parameter を明示することで、 コンパイラに教えている。 この場合だと、x をリターンしているので、コンパイラでも検出できると思うが、以下のような場合を考えると、省略ルールから外れた場合は常に指定する必要があるというのは、デザインとして納得ができる。

fn f<'a> (x: &'a i32, y: &'a i32) -> &'a i32 {
    if *x == 0 {
        x
    } else {
        y
    }
}

ちなみに、最初の例で、f(&y, &x) とすると、y はスコープアウトするのに r に参照がわたってしまうので、コンパイルエラーになる。 こんな感じで rust は安全性を担保してるようだ。

複数の Trait による Restriction

Generics の restriction に複数の trait を指定したい場合、+ を使えばいいらしい。

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}

trait HasArea {
    fn area(&self) -> f64;
}

trait HasPoint {
    fn point(&self) -> (f64, f64);
}

impl HasArea for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

impl HasPoint for Circle {
    fn point(&self) -> (f64, f64) {
        (self.x, self.y)
    }
}

fn print_area_and_point<T: HasArea+HasPoint>(c: T) {
    println!("area is {}, {}", c.area(), c.point());
}

fn main() {
    let c = Circle{x: 0.0, y:0.0, radius: 1.0};
    print_area_and_point(c);
}

http://melpon.org/wandbox/permlink/TH9xztDKwDhjoyYz

Rust のポインタ

rust が提供するポインタは、以下の3つがあるらしい。

  • reference
  • Box
  • Rc/Arc

また、基本的なルールとして、リーダブル(immutable)なポインタは同時に複数作れて、ライタブル(mutable)なポインタは一度に一つしか作れない。 これをownershipとかいうらしい。 複数の人がかけたら、値が不定になるからそれを防ぐためのようだ。

3つのポインタはC++な人には、以下の対応付けで考えればわかりやすい。

rust c++
reference reference
Box std::unique_ptr
Rc/Arc std::shared_ptr

Rc と Arc の違いは、thread と組み合わせられるかどうか。 atomically reference counted の略らしい。 C++ の shared_ptr は thread 対応なのでカウンタのロックが必要でパフォーマンスが云々みたいな話があるが、 rust は用途別に用意したようだ。

rust 始めます

新年になったし、そろそろ1.0が近いらしいので、Rust 始めます。

まずは環境設定から。 手元の環境は、arch linuxなのでpacmanでさくっと入る。

$ sudo pacman -S rust

エディタはemacsなのでpackage.elでこれまたさくっと入る。

  • rust-mode
  • flycheck
  • quickrun

あとはguideでもやろうかと。

※追記 guide で cargo が必要になったので、追加インストール。 pacaur を使っているが、yaourt なり makepkg なりお好みで。

$ pacaur -S cargo-nightly-bin