ことの発端

最近、Rustに入門しました。
どんな言語も課題があると習得も早いだろうってことで、まずはReactiveXをRustで実装してみました。1
ReactiveXは関数型や非同期を扱うライブラリで、ほぼすべてがジェネリクスで構成されます。
その中で、なかなかスンナリ入ってこなかったのが static でした。

で、個人的に色々とやってみて、「なるほど」となったので記事にしてみました。

Rust の static

まず、C++のstaticとは似て非なるものです。
罪悪感を抱えながら「今日もstatic(グローバルステート)を増やしてしまった。。。」的な「あのstatic」ではありません。

まず、Rust の static には2種類あります。

    1. staticライフタイム

 

    staticライフタイム境界

staticライフタイムは C++ の static と同じです。
が、しかし、Rustではプリミティブ型やリテラルだけが static 定義できます。つまり、オブジェクトは static ライフタイムが使えません。Singletonパターンを使ってグローバルステートを実装することはできますが、staticライフタイムなオブジェクトは作れません。

ほいで、次の staticライフタイム境界 が曲者です。

staticライフタイム境界 とは

ざっくりいうと、

「 参 照 が 含 ま れ な い も の 」

です。

参照は所有者が居てその所有者が手放すまでが生存期間(ライフタイム)になりますが、その参照が含まれていなければ全てstaticライフタイム境界です。(もうね〜、何というか、言い方変えて欲しい。。。)

具体的にコードで実証してみます。

staticライフタイム境界 を感じる

準備

まず、こんなコードを書きます。

fn is_static<T>(_: T)
where
  T: 'static,  // <-- これが 「satticライフタイム境界」 というヤツです。
{}

これはstaticライフタイム境界の変数を渡さないとコンパイルエラーになる関数です。
この関数に色々と値を渡してみると理解が早いかもです。

リテラル

C++erは、この時点で「??」ですが、これが先述のstaticライフタイム境界です。

  is_static(123);

実体をmove

  let x = 0;
  is_static(x);

参照

「参照が含まれるもの」というか、参照そのものもNGです。

  let x = 0;
  is_static(&x);

クロージャー(外部変数のキャプチャなし)

C++ ではラムダ式です。

  let f = || {};
  is_static(f);

クロージャー(参照でキャプチャ)

クロージャーは外部変数のキャプチャしているオブジェクトです。
このキャプチャしている変数は move を指定しないと参照になります。

  let x = 0;
  let f = || println!("{}", x);
  is_static(f);

クロージャー(moveでキャプチャ)

move すればクロージャー内は実体を所有することになるので、無問題。

  let x = 0;
  let f = move || println!("{}", x);
  is_static(f);

‘static str&

staticライフタイムの参照は許されます。

  let a = "abc";  // <--  &'static str
  is_static(a);

所感

やっぱり static と書くのは抵抗がある。。w

ちょっとだけ本気で作ってみた -> another-rxrust ↩

bannerAds