よくあるエラーと対処法
Rust学習中に遭遇しやすいエラーとその解決方法をまとめました。
所有権関連のエラー
E0382: value borrowed after move
エラーメッセージ
error[E0382]: borrow of moved value: `s`
--> src/main.rs:4:20
|
2 | let s = String::from("hello");
| - move occurs because `s` has type `String`
3 | let s2 = s;
| - value moved here
4 | println!("{}", s);
| ^ value borrowed here after move
原因: 値が別の変数にムーブされた後に使用しようとしている
解決方法:
#![allow(unused)]
fn main() {
// 方法1: クローンする
let s = String::from("hello");
let s2 = s.clone();
println!("{}", s); // OK
// 方法2: 参照を使う
let s = String::from("hello");
let s2 = &s;
println!("{}", s); // OK
}
E0502: cannot borrow as mutable because it is also borrowed as immutable
エラーメッセージ
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:4:5
|
3 | let first = &v[0];
| - immutable borrow occurs here
4 | v.push(4);
| ^^^^^^^^^ mutable borrow occurs here
5 | println!("{}", first);
| ----- immutable borrow later used here
原因: 不変参照がある間に可変操作をしようとしている
解決方法:
#![allow(unused)]
fn main() {
// 方法1: 不変参照を先に使い切る
let mut v = vec![1, 2, 3];
let first = &v[0];
println!("{}", first); // ここで使い切る
v.push(4); // その後で変更
// 方法2: インデックスを保存する
let mut v = vec![1, 2, 3];
let first_idx = 0;
v.push(4);
println!("{}", v[first_idx]);
}
E0499: cannot borrow as mutable more than once
エラーメッセージ
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> src/main.rs:4:17
|
3 | let r1 = &mut x;
| ------ first mutable borrow occurs here
4 | let r2 = &mut x;
| ^^^^^^ second mutable borrow occurs here
5 | println!("{}, {}", r1, r2);
| -- first borrow later used here
原因: 可変参照を同時に複数作ろうとしている
解決方法:
#![allow(unused)]
fn main() {
// 方法1: 順番に使う
let mut x = 5;
let r1 = &mut x;
*r1 += 1;
// r1のスコープ終了
let r2 = &mut x;
*r2 += 1;
// 方法2: ブロックでスコープを分ける
let mut x = 5;
{
let r1 = &mut x;
*r1 += 1;
}
{
let r2 = &mut x;
*r2 += 1;
}
}
ライフタイム関連のエラー
E0106: missing lifetime specifier
エラーメッセージ
error[E0106]: missing lifetime specifier
--> src/main.rs:1:33
|
1 | fn longest(x: &str, y: &str) -> &str {
| ---- ---- ^ expected named lifetime parameter
原因: 複数の参照を受け取って参照を返す関数でライフタイムが不明
解決方法:
#![allow(unused)]
fn main() {
// ライフタイム注釈を追加
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
}
E0597: borrowed value does not live long enough
エラーメッセージ
error[E0597]: `x` does not live long enough
--> src/main.rs:4:9
|
3 | let r;
| - borrow later stored here
4 | let x = 5;
5 | r = &x;
| ^^ borrowed value does not live long enough
6 | }
| - `x` dropped here while still borrowed
原因: 参照先がスコープを抜けて無効になる
解決方法:
#![allow(unused)]
fn main() {
// 参照先を外側のスコープに移動
let x = 5;
let r = &x;
println!("{}", r);
}
型関連のエラー
E0308: mismatched types
エラーメッセージ
error[E0308]: mismatched types
--> src/main.rs:2:18
|
2 | let x: i32 = "hello";
| --- ^^^^^^^ expected `i32`, found `&str`
| |
| expected due to this
原因: 期待される型と実際の型が一致しない
解決方法:
#![allow(unused)]
fn main() {
// 正しい型を使う
let x: i32 = 42;
// または型注釈を省略
let x = "hello";
}
E0277: the trait bound is not satisfied
エラーメッセージ
error[E0277]: the trait bound `MyStruct: std::fmt::Debug` is not satisfied
--> src/main.rs:5:22
|
5 | println!("{:?}", my_struct);
| ^^^^^^^^^ `MyStruct` cannot be formatted using `{:?}`
原因: 必要なトレイトが実装されていない
解決方法:
// deriveでトレイトを実装
#[derive(Debug)]
struct MyStruct {
value: i32,
}
fn main() {
let my_struct = MyStruct { value: 42 };
println!("{:?}", my_struct); // OK
}
Option/Result関連のエラー
cannot use ? in a function that returns ()
エラーメッセージ
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option`
--> src/main.rs:3:13
|
3 | let f = File::open("file.txt")?;
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
原因: ?演算子はResultかOptionを返す関数でしか使えない
解決方法:
// 方法1: 関数の戻り値をResultにする
fn main() -> Result<(), std::io::Error> {
let f = File::open("file.txt")?;
Ok(())
}
// 方法2: matchでハンドリング
fn main() {
match File::open("file.txt") {
Ok(f) => { /* 処理 */ },
Err(e) => eprintln!("Error: {}", e),
}
}
// 方法3: unwrap(エラー時はパニック)
fn main() {
let f = File::open("file.txt").unwrap();
}
method unwrap not found
エラーメッセージ
error[E0599]: no method named `unwrap` found for type `i32`
原因: unwrapはOptionやResultのメソッドで、普通の値には使えない
解決方法:
#![allow(unused)]
fn main() {
// Optionを返す関数の結果に使う
let v = vec![1, 2, 3];
let first = v.get(0).unwrap(); // get()はOption<&T>を返す
}
モジュール関連のエラー
E0432: unresolved import
エラーメッセージ
error[E0432]: unresolved import `crate::models`
--> src/main.rs:1:5
|
1 | use crate::models;
| ^^^^^^^^^^^^^ no `models` in the root
原因: モジュールが正しく宣言されていない
解決方法:
#![allow(unused)]
fn main() {
// main.rs または lib.rs でモジュールを宣言
mod models; // これを追加
use crate::models::User;
}
ファイル構造:
src/
├── main.rs # mod models; を宣言
└── models.rs # または models/mod.rs
E0603: function is private
エラーメッセージ
error[E0603]: function `internal_function` is private
--> src/main.rs:3:14
|
3 | my_module::internal_function();
| ^^^^^^^^^^^^^^^^^ private function
原因: 非公開の関数にアクセスしようとしている
解決方法:
#![allow(unused)]
fn main() {
// 関数をpubにする
pub fn internal_function() {
// ...
}
}
非同期関連のエラー
future cannot be sent between threads safely
エラーメッセージ
error: future cannot be sent between threads safely
原因: 非同期タスク内でSendでない値を使っている
解決方法:
#![allow(unused)]
fn main() {
// 方法1: Arcでラップ
use std::sync::Arc;
let data = Arc::new(data);
// 方法2: 値をクローンしてタスクに渡す
let data = data.clone();
tokio::spawn(async move {
// data を使用
});
}
async block/function expected but found fn
エラーメッセージ
error: `await` is only allowed inside `async` functions and blocks
原因: asyncでない関数内でawaitを使っている
解決方法:
#![allow(unused)]
fn main() {
// 関数をasyncにする
async fn my_function() {
let result = some_async_fn().await;
}
}
コンパイル時のヒント
未使用の変数警告
warning: unused variable: `x`
--> src/main.rs:2:9
|
2 | let x = 5;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
解決方法:
#![allow(unused)]
fn main() {
// 使う予定がない場合はアンダースコアを付ける
let _x = 5;
// または完全に無視
let _ = some_function();
}
デバッグのコツ
1. 型を確認する
#![allow(unused)]
fn main() {
// コンパイラに型を教えてもらう
let x: () = some_expression; // エラーメッセージで型がわかる
}
2. 中間値を出力する
#![allow(unused)]
fn main() {
// dbg!マクロを使う
let result = dbg!(some_function());
// 出力: [src/main.rs:2] some_function() = 42
}
3. コンパイラの提案を読む
help: consider borrowing here: `&v`
Rustコンパイラは多くの場合、修正方法を提案してくれます。help:の行を注意深く読みましょう。
まとめ
| エラー種別 | 主な原因 | 対処法 |
|---|---|---|
| E0382 | ムーブ後の使用 | clone()または参照を使う |
| E0502 | 借用ルール違反 | 参照の使用順序を変える |
| E0106 | ライフタイム不明 | ライフタイム注釈を追加 |
| E0308 | 型の不一致 | 正しい型を使う |
| E0277 | トレイト未実装 | deriveまたは手動実装 |
エラーメッセージを落ち着いて読み、コンパイラの提案に従うことが大切です。