Rustのエラー[E0106]: missing lifetime specifierを修正する

intermediate🦀 Rust2026-03-18| Rust 1.40以降(全エディション)、任意のOS(Linux、macOS、Windows)

Error Message

error[E0106]: missing lifetime specifier
#rust#ライフタイム#参照#アノテーション

TL;DR

コードのどこかに、構造体フィールド・関数シグネチャ・implブロック内に参照(&T)があり、Rustはその有効期間を判断できません。修正方法は'aのような名前付きライフタイムパラメータを追加することです。これにより、参照の有効性が周囲の型や関数とどのように関連するかをコンパイラに正確に伝えます。

// 修正前(コンパイルエラー)
struct Config {
    name: &str,  // error[E0106]: missing lifetime specifier
}

// 修正後(正常)
struct Config<'a> {
    name: &'a str,
}

このエラーが発生する原因

Rustはすべての参照がどの期間有効かを追跡します—これはコンパイル時に強制されるメモリ安全性の保証です。参照が構造体フィールドや複数の参照を持つ関数シグネチャに現れると、コンパイラはどの参照がどれより長生きするかを伝えるライフタイム注釈という明示的なガイダンスを必要とします。

最もよく発生する箇所は3つです:

  • 参照(&str&T)を保持する構造体フィールド
  • 参照を返し、複数の参照パラメータを受け取る関数
  • ライフタイムパラメータを持つ構造体のimplブロック

Rustの*ライフタイム省略規則(elision rules)*は多くの単純なケースを自動的に処理します。ただし、すべてのパターンをカバーするわけではなく、省略規則で解決できない場合にerror[E0106]が発生します。

修正方法1 — 参照フィールドを持つ構造体

これが最も一般的なエラーの原因です。構造体にライフタイムパラメータを追加し、各参照フィールドにそれを注釈します。

// エラーあり
struct Article {
    title: &str,
    body: &str,
}

// 修正後
struct Article<'a> {
    title: &'a str,
    body: &'a str,
}

Articleを作成または使用するコードはライフタイムを持つことになりますが、実際にはコンパイラが省略(elision)を通じてほとんどの呼び出し箇所を自動的に処理します:

fn print_article(article: &Article) {  // Rustが省略 — 問題なし
    println!("{}", article.title);
}

fn main() {
    let title = String::from("Rustのライフタイム");
    let body  = String::from("安全を守ってくれます。");
    let article = Article {
        title: &title,
        body:  &body,
    };
    print_article(&article);
}

修正方法2 — 参照を返す関数

関数から参照を返す場合、Rustはどの入力から来たものかを知る必要があります。入力参照が1つなら省略規則で処理されます。2つ以上の場合は明示的に注釈が必要です。

// エラーあり — 戻り値が`a`と`b`どちらから借用しているかRustは判断できない
fn longest(a: &str, b: &str) -> &str {
    if a.len() > b.len() { a } else { b }
}

// 修正後 — 両引数がライフタイム'aを共有し、出力はその期間内のみ有効
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() > b.len() { a } else { b }
}

'aの注釈は「戻り値の参照は両方のabが有効である間だけ有効」という意味です。実際には、2つのライフタイムのうち短い方が適用されます。

修正方法3 — ライフタイムを持つ構造体のimplブロック

ライフタイムパラメータを持つ構造体のメソッドは、implキーワード自体にも同じライフタイムが必要です。これを忘れるのはよくある間違いです。

struct Parser<'a> {
    input: &'a str,
    pos: usize,
}

// エラーあり
impl Parser {
    fn remaining(&self) -> &str {
        &self.input[self.pos..]
    }
}

// 修正後
impl<'a> Parser<'a> {
    fn remaining(&self) -> &str {
        &self.input[self.pos..]
    }
}

修正方法4 — データを所有することを検討する

ライフタイムが全く適切でないケースもあります。'aをあちこちに追加するとコードが追いにくくなる場合は、データを完全に所有する方法を検討してください:

// &strを借用する代わりに...
struct Config<'a> {
    name: &'a str,
}

// ...Stringで所有する
struct Config {
    name: String,
}

ヒープアロケーションのコストはわずかにかかりますが、構造体はシンプルになり、受け渡しもはるかに容易になります。ホットパスや外部APIからの借用スライスを直接扱う場合でなければ、通常はこのトレードオフが有利です。

修正を確認する

プロジェクトをリビルドしましょう:

cargo build

出力にerror[E0106]がなければライフタイムは解決されています。ついでに、コンパイラが見逃した可能性のあるライフタイムのアンチパターンを検出するためにClippyを実行しましょう:

cargo clippy

どのアノテーションを使うか迷っている場合はコンパイラに直接確認しましょう:

rustc --explain E0106

このコマンドはブラウザ不要で、ターミナル上に例付きの完全な説明を表示します。

判断の手引き

  • &str&Tフィールドを持つ構造体 → 構造体に<'a>を追加してフィールドに注釈をつける。
  • 複数の入力参照から参照を返す関数 → 出力がどの入力から借用しているかを注釈する。
  • ライフタイムを持つ構造体のimplブロックimpl<'a> MyStruct<'a>にライフタイムパラメータをミラーする。
  • その他の場合 → 所有型への切り替えを検討する(&strの代わりにString&[T]の代わりにVec<T>)。

Related Error Notes