Rustlings Arena
← アリーナに戻る

よくある Rust コンパイラエラー

最もよくある Rust エラーを例と修正方法付きで解説。

E0382

移動済みの値の使用

error[E0382]: use of moved value: `s1`

ヒープに割り当てられた値(String や Vec など)を別の変数に代入すると、所有権は新しい変数に移動します。元の変数はなくなります——その後は使用できません。これは Rust の所有権システムが use-after-free バグをコンパイル時に排除するものです。

❌ Broken
let s1 = String::from("hello");
let s2 = s1;          // s1 moves into s2
println!("{}", s1);   // ❌ E0382: s1 was moved
✅ Fixed
let s1 = String::from("hello");
let s2 = s1.clone();  // deep copy — both stay valid
println!("{} {}", s1, s2); // ✅

// Or borrow instead of moving:
let s2 = &s1;
println!("{} {}", s1, s2); // ✅
💡 Tip: プリミティブ型(i32、bool、char、f64)は Copy を実装しており、自動的に複製されます。ヒープ型(String、Vec、Box)は移動します。
E0502

可変として借用できない——不変として借用済み

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable

Rust は多数の共有(&)参照か、ひとつの排他的(&mut)参照を許可します——同時には不可。アクティブな不変借用がある場合、不変借用が終わるまで可変借用を取ることができません。このルールはデータ競合をその構造上排除します。

❌ Broken
let mut v = vec![1, 2, 3];
let first = &v[0];    // immutable borrow
v.push(4);            // ❌ E0502: mutable borrow while immutable exists
println!("{}", first);
✅ Fixed
let mut v = vec![1, 2, 3];
let first = v[0];     // copy the value out (i32 is Copy)
v.push(4);            // ✅ no active borrow
println!("{}", first);

// Or restructure scope:
let mut v = vec![1, 2, 3];
{
    let first = &v[0];
    println!("{}", first);
}   // first's borrow ends here
v.push(4);            // ✅
💡 Tip: 借用チェッカーは保守的です。戦っている場合は、println を前に移動する、借用の代わりに値をコピーする、または .clone() を使ってみてください。
E0499

可変として 2 回以上借用できない

error[E0499]: cannot borrow `v` as mutable more than once at a time

可変参照(&mut)は同時にひとつしか存在できません。これはシングルスレッドコードのデータ競合を防ぎ、Rust の並行性保証を機能させる基本的なルールです。

❌ Broken
let mut v = vec![1, 2, 3];
let a = &mut v;
let b = &mut v;   // ❌ E0499: second mutable borrow
a.push(4);
b.push(5);
✅ Fixed
let mut v = vec![1, 2, 3];
{
    let a = &mut v;
    a.push(4);
}   // a's borrow ends here
let b = &mut v;   // ✅ now safe
b.push(5);
💡 Tip: スコープ {} を使って可変借用の生存期間を制限しましょう。実際にはこのエラーは、変更が順次行われるようにロジックを再構成することを意味することが多いです。
E0308

型の不一致

error[E0308]: mismatched types expected `i32`, found `&i32`

コンパイラが推論または期待する型が、提供した型と一致しません。イテレータで反復する場合(イテレータは参照を生成する)、関数が値の代わりに () を返す場合、または符号付き/符号なし整数を混在させる場合に非常によく見られます。

❌ Broken
// Trailing semicolon returns () instead of i32:
fn double(n: i32) -> i32 {
    n * 2;   // ❌ E0308: returns () not i32
}

// Iterator reference confusion:
let nums = vec![1, 2, 3];
let sum: i32 = nums.iter().sum(); // needs type annotation
✅ Fixed
fn double(n: i32) -> i32 {
    n * 2    // ✅ no semicolon — expression returned
}

// Dereference in closures when iterating:
let nums = vec![1, 2, 3];
let doubled: Vec<i32> = nums.iter().map(|&x| x * 2).collect();
//                                       ^ dereference the &i32
💡 Tip: 関数の最後の行の末尾のセミコロンは、戻り型を () に静かに変えてしまいます。これは Rust での初心者の最も多い間違いです。
E0277

トレイト境界が満たされていない

error[E0277]: `MyType` doesn't implement `std::fmt::Display`

型が必要なトレイトを実装していません。{} フォーマットを Display なしで使おうとした場合、PartialOrd なしで型を比較しようとした場合、または特定のトレイトを必要とするメソッドを呼び出した場合に最もよく発生します。

❌ Broken
struct Point { x: i32, y: i32 }

let p = Point { x: 1, y: 2 };
println!("{}", p);  // ❌ E0277: Point doesn't implement Display
println!("{:?}", p); // also fails — needs Debug
✅ Fixed
#[derive(Debug)]
struct Point { x: i32, y: i32 }

let p = Point { x: 1, y: 2 };
println!("{:?}", p);  // ✅ Debug via #[derive(Debug)]

// Implement Display manually for custom formatting:
use std::fmt;
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}
println!("{}", p);  // ✅
💡 Tip: {:?} 印刷には #[derive(Debug)] を追加してください。{} 印刷には std::fmt::Display を手動で実装してください。ほとんどの欠けている境界は Debug、Display、Clone、PartialEq、または PartialOrd です。
E0106

ライフタイム指定子がない

error[E0106]: missing lifetime specifier expected named lifetime parameter

関数が参照を返し、複数の参照パラメータを持つ場合、Rust は出力参照がどの入力から来るかを推論できません。ライフタイムアノテーションで教える必要があります。

❌ Broken
// Compiler doesn't know if the return borrows from x or y:
fn longest(x: &str, y: &str) -> &str {   // ❌ E0106
    if x.len() > y.len() { x } else { y }
}
✅ Fixed
// 'a says: output lives no longer than the shorter input
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {  // ✅
    if x.len() > y.len() { x } else { y }
}

// Single input → no annotation needed (elision rule):
fn first_word(s: &str) -> &str {  // ✅ lifetime elided
    let bytes = s.as_bytes();
    for (i, &b) in bytes.iter().enumerate() {
        if b == b' ' { return &s[..i]; }
    }
    &s[..]
}
💡 Tip: ライフタイムアノテーションは制約であり、期間ではありません。'a は「出力は入力より長く生きられない」を意味します。ほとんどのライフタイムは推論されます(省略)。コンパイラが関係を把握できない場合にのみ明示的なものが必要です。
E0596

可変として借用できない——可変として宣言されていない

error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable

mut で宣言されていない変数を変更しようとしました。Rust では変数はデフォルトで不変です——コンパイラはこれを強制するため、意図しない変更はコンパイル時に検出されます。

❌ Broken
let x = 5;
x = 10;        // ❌ E0596: x is immutable

let v = vec![1, 2, 3];
v.push(4);     // ❌ E0596: v is immutable
✅ Fixed
let mut x = 5;   // ✅ mut makes it mutable
x = 10;

let mut v = vec![1, 2, 3];
v.push(4);     // ✅
💡 Tip: let の後に mut を追加してください。変数が実際に変化する必要がある場合にのみ mut を追加しましょう——デフォルトの不変性はバグを捕捉し、コードを推論しやすくします。
E0384

不変変数に 2 回代入できない

error[E0384]: cannot assign twice to immutable variable `x`

E0596 に似ていますが、メソッド呼び出しではなく 2 回目の代入によって発生します。変数が mut なしで宣言されましたが、再代入しようとしました。

❌ Broken
let x = 5;
x = 10;  // ❌ E0384
✅ Fixed
let mut x = 5;
x = 10;  // ✅

// Shadowing is another option if you want to "replace" the variable:
let x = 5;
let x = 10;  // ✅ shadowing — creates a new binding named x
💡 Tip: シャドーイング(let x = ...)と変更(mut x = ...)は似ていますが異なります:シャドーイングは新しい変数を作成し(型を変更できる)、変更は同じバインディングを変更します。
E0507

借用されたコンテンツから移動できない

error[E0507]: cannot move out of `*s` which is behind a shared reference

参照から値を移動しようとしました。&T を通じて所有権を取ることはできません——参照はデータを所有していません。

❌ Broken
fn print_name(s: &String) {
    let owned = *s;  // ❌ E0507: can't move out of &String
    println!("{}", owned);
}
✅ Fixed
fn print_name(s: &String) {
    let owned = s.clone();  // ✅ clone the data
    println!("{}", owned);
}

// Or just use the reference directly:
fn print_name(s: &String) {
    println!("{}", s);  // ✅ no need to own it
}
💡 Tip: 値を読むだけでよい場合は、参照を直接使ってください。所有されたコピーが必要な場合は .clone() を呼び出してください。所有権が必要な場合は、パラメータを &T ではなく T を取るように変更してください。
E0004

match の網羅的でないパターン

error[E0004]: non-exhaustive patterns: `None` not covered

match 式はすべての可能なケースを処理しなければなりません。バリアントが未処理の場合、コードはコンパイルされません。これにより、未処理のケースがクラッシュを引き起こすランタイムバグのクラス全体が排除されます。

❌ Broken
let opt: Option<i32> = Some(42);
match opt {
    Some(n) => println!("{}", n),
    // ❌ E0004: None not covered
}
✅ Fixed
match opt {
    Some(n) => println!("{}", n),
    None    => println!("nothing"),  // ✅ exhaustive
}

// Use _ as a catch-all:
match opt {
    Some(n) => println!("{}", n),
    _       => {},  // ✅ handles everything else
}

// Or use if let for a single case:
if let Some(n) = opt {
    println!("{}", n);  // ✅ no else needed
}
💡 Tip: コンパイラはどのバリアントが欠けているかを正確に教えてくれます。_ はキャッチオール。if let はひとつのパターンだけを扱う場合の省略形です。
E0072

再帰型のサイズが無限

error[E0072]: recursive type `List` has infinite size

各バリアントが直接自身を含む再帰型は、割り当てに無限のメモリが必要になります。Rust はコンパイル時にすべての型のサイズを知る必要があります。解決策は Box を通じた間接参照です。Box は既知のポインタサイズを持ちます。

❌ Broken
enum List {
    Cons(i32, List),  // ❌ E0072: infinite size
    Nil,
}
✅ Fixed
enum List {
    Cons(i32, Box<List>),  // ✅ Box has fixed pointer size (8 bytes)
    Nil,
}

let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
💡 Tip: Box<T> は最もシンプルなヒープポインタです。T に関わらず固定サイズ(1 ポインタ幅)を持ち、再帰的なサイズ計算を断ち切ります。
E0716

借用中に一時的な値がドロップされた

error[E0716]: temporary value dropped while borrowed

一時的な値を作成し、それへの参照を取り、その一時的な値が参照が使われる前にドロップされました。参照はダングリングになります——解放されたメモリを指してしまいます。

❌ Broken
let s: &str = &String::from("hello")
    .to_uppercase();  // ❌ E0716: temporary dropped

// Also common with chains:
let name = get_user().name;  // if get_user() returns a temp
✅ Fixed
// Bind the temporary to a variable first:
let upper = String::from("hello").to_uppercase();
let s: &str = &upper;  // ✅ upper lives long enough
println!("{}", s);
💡 Tip: このエラーが出たら、中間値を保持する変数を導入してください。let バインディングのライフタイムはブロックの終わりまで延びます。
E0515

ローカル変数を参照する値を返せない

error[E0515]: cannot return value referencing local variable `local`

ローカル変数への参照を返そうとしました。関数が返るとき、ローカル変数はドロップされ、ダングリング参照が残ります。Rust はこれをコンパイル時に防ぎます。

❌ Broken
fn get_greeting() -> &str {
    let s = String::from("hello");
    &s   // ❌ E0515: s is dropped when function returns
}
✅ Fixed
// Return an owned value:
fn get_greeting() -> String {
    String::from("hello")  // ✅ caller owns it
}

// Or return a &'static str literal:
fn get_greeting() -> &'static str {
    "hello"  // ✅ lives for the entire program
}
💡 Tip: 参照を返す必要がある場合、それは関数の入力(パラメータからの借用)から来るか、'static でなければなりません。迷った場合は、所有された型(String、Vec など)を返してください。
E0369

二項演算を適用できない

error[E0369]: binary operation `>` cannot be applied to type `T`

ジェネリック型 T に演算子を使いましたが、T にはその演算子が存在することを要求するトレイト境界がありません。ジェネリックコードは型がサポートする演算について明示的でなければなりません。

❌ Broken
fn largest<T>(list: &[T]) -> &T {
    let mut biggest = &list[0];
    for item in list {
        if item > biggest {  // ❌ E0369: T doesn't implement PartialOrd
            biggest = item;
        }
    }
    biggest
}
✅ Fixed
fn largest<T: PartialOrd>(list: &[T]) -> &T {  // ✅ add bound
    let mut biggest = &list[0];
    for item in list {
        if item > biggest {
            biggest = item;
        }
    }
    biggest
}
💡 Tip: E0369 が出た場合、エラーメッセージが必要なトレイトを教えてくれます:比較には PartialOrd、+ には Add、{} には Display など。境界として追加してください:<T: TraitName>。
E0428

名前が複数回定義されている

error[E0428]: the name `connect` is defined multiple times

同じスコープ内で 2 つのアイテム(関数、構造体、型など)を同じ名前で定義しました。Rust はこれを許可しません——名前はモジュール内で一意でなければなりません。

❌ Broken
fn connect() -> String { "tcp".into() }
fn connect() -> String { "udp".into() }  // ❌ E0428: duplicate
✅ Fixed
fn connect_tcp() -> String { "tcp".into() }
fn connect_udp() -> String { "udp".into() }  // ✅ unique names

// Or use a parameter:
fn connect(protocol: &str) -> String { protocol.into() }
💡 Tip: これは use 文が競合する名前をインポートする場合にも発生します。as を使って名前を変更してください:use std::io::Error as IoError;
E0061

引数の数が間違っている

error[E0061]: this function takes 2 arguments but 3 arguments were supplied

関数のシグネチャが宣言する数より多いまたは少ない引数で関数を呼び出しました。Rust はデフォルトパラメータや可変長引数関数(println! などのマクロを除く)をサポートしていません。

❌ Broken
fn add(a: i32, b: i32) -> i32 { a + b }

add(1, 2, 3);  // ❌ E0061: 3 args, expected 2
add(1);        // ❌ E0061: 1 arg, expected 2
✅ Fixed
add(1, 2);  // ✅

// For optional parameters, use Option:
fn greet(name: &str, title: Option<&str>) {
    match title {
        Some(t) => println!("{} {}", t, name),
        None    => println!("{}", name),
    }
}
greet("Alice", None);
greet("Bob", Some("Dr."));
💡 Tip: Rust にはデフォルトパラメータがありません。省略可能な値には Option<T> を、多くの省略可能フィールドを持つ関数にはビルダー構造体を使ってください。
E0433

解決失敗——スコープ内に見つからない

error[E0433]: failed to resolve: use of undeclared crate or module `HashMap`

スコープ内にない型や関数を使いました。プレリュード以外の標準ライブラリ型(HashMap、BTreeMap、BufReader など)には明示的な use 文が必要です。

❌ Broken
let mut map = HashMap::new();  // ❌ E0433: HashMap not in scope
✅ Fixed
use std::collections::HashMap;

let mut map = HashMap::new();  // ✅

// Common imports:
use std::collections::{HashMap, HashSet, BTreeMap};
use std::io::{self, BufRead, Write};
use std::fmt;
💡 Tip: Rust のプレリュードは一般的な型(Vec、String、Option、Result など)を自動的にインポートします。それ以外はすべて明示的な use が必要です。Rust Analyzer が正しい use パスを提案してくれます。

セミコロンが必要 / 式が必要

error: expected `;`, found `let` error: expected expression, found keyword `fn`

構文エラー——パーサーが予期しないものを見つけました。通常は、セミコロンの欠落、閉じられていない区切り文字、キーワードのタイポ、または式の誤配置です。

❌ Broken
fn main() {
    let x = 5     // ❌ missing semicolon
    let y = 10;

    fn inner() {} // ❌ nested fn needs to be at statement level
    x + y         // if this is a statement, not a return, add ;
}
✅ Fixed
fn main() {
    let x = 5;     // ✅ semicolon added
    let y = 10;

    fn helper() {}  // ✅ nested fn is valid in Rust
    println!("{}", x + y);
}
💡 Tip: Rust のエラーメッセージはほぼ常に正しい行を指します。セミコロンエラーがおかしいと感じたら、前の行を確認してください——前の文の ; の欠落がパーサーを奇妙な状態にします。

要件評価のオーバーフロー

error[E0275]: overflow evaluating the requirement `Box<T>: Sized`

コンパイラがトレイト境界を証明しようとして無限ループに陥りました。最もよくある原因は、再帰的なトレイト実装、または自身を必要とするトレイトを実装しようとする型です。

❌ Broken
// Generic function calling itself with an incompatible bound:
fn process<T: Clone>(x: T) {
    process(x.clone()); // infinite recursion in type inference
}
✅ Fixed
// Add a base case or restructure logic:
fn process(x: String) {
    if x.is_empty() { return; }
    process(x[1..].to_string());
}
💡 Tip: このエラーはほぼ常に再帰型またはトレイト境界のループを指します。トレイト制約を単純化するか、明示的な型パラメータを追加してください。

このスコープで値が見つからない

error[E0425]: cannot find value `x` in this scope

現在のスコープに存在しない変数を参照しました。よくある原因:変数名のタイポ、終了した内側のブロックで宣言された変数、ループの外でループ変数を使用。

❌ Broken
{
    let x = 5;
}
println!("{}", x);  // ❌ x is out of scope

for i in 0..10 { }
println!("{}", i);  // ❌ i only lives inside the for loop
✅ Fixed
let x = 5;         // declare outside the block
{
    println!("{}", x); // ✅ x is in scope
}
println!("{}", x); // ✅ still in scope

// Save the last loop value explicitly:
let mut last = 0;
for i in 0..10 { last = i; }
println!("{}", last);  // ✅
💡 Tip: Rust のスコープはブロックベースです。変数は宣言された場所から囲むブロックの終わりまでしか存在しません。より広いスコープが必要な場合は、宣言を上に移動してください。
🦀

始める準備はできましたか?

26 の無料インタラクティブチャレンジ。インストール不要。アカウント不要ですぐ開始。

Rust を学び始める →