LoginSignup
4
1

More than 1 year has passed since last update.

Rust の static を感じる

Last updated at Posted at 2023-04-08

ことの発端

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

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

Rust の static

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

まず、Ruststatic には2種類あります。

  1. staticライフタイム
  2. 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ライフタイム境界です。

パターン1(OK)
  is_static(123);

実体をmove

パターン2(OK)
  let x = 0;
  is_static(x);

参照

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

パターン3(NG)
  let x = 0;
  is_static(&x);

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

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

パターン4(OK)
  let f = || {};
  is_static(f);

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

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

パターン5(NG)
  let x = 0;
  let f = || println!("{}", x);
  is_static(f);

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

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

パターン6(OK)
  let x = 0;
  let f = move || println!("{}", x);
  is_static(f);

'static str&

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

パターン7(OK)
  let a = "abc";  // <--  &'static str
  is_static(a);

所感

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

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

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1