エラーの内容
cargo build を実行すると、コンパイラが処理を止めます:
error[E0308]: mismatched types
--> src/main.rs:5:18
|
5 | let x: i32 = "hello";
| --- ^^^^^^^ expected `i32`, found `&str`
|
= note: expected type `i32`
found type `&str`
ビルドが失敗します。Rustは型不一致のあるコードをコンパイルしません — 暗黙の型変換も、暗黙のキャストも、「だいたい合っていればOK」という処理も一切ありません。変数 x は i32 として宣言されていますが、文字列リテラルが代入されています。Rustではこれは完全なエラーです。
なぜこのエラーが発生するのか
Rustは静的型付け言語です。すべての変数はコンパイル時に厳密にひとつの型を持ちます。間違った型を代入すると、コンパイラは容赦なく拒否します。例外はありません。
これは実際のバグを早期に検出するための仕組みです。Cでの暗黙の型変換は警告なしに64ビット値を32ビットに切り捨てることがありますが、Rustは明示的な処理を強制します。その代わり、型について曖昧にはできません — それがRustの設計思想です。
主な発生原因:
- 代入する値に対して変数の型アノテーションが間違っている
- 関数から間違った型を返している
Stringが期待される場所に&strを渡している(またはその逆)i32、u32、usizeなどの整数型を混在させている- 裸の
Tが期待される場所でOption<T>の値を使っている
修正方法
修正1: 型アノテーションを修正する
値は正しいがアノテーションが間違っている場合は、アノテーションを修正します:
// 修正前(アノテーションが間違っている)
let x: i32 = "hello"; // error: expected i32, found &str
// 修正後(アノテーションが値と一致している)
let x: &str = "hello"; // OK
// またはRustに型推論させる
let x = "hello"; // &str として推論される
修正2: 値を修正する
型アノテーションが意図通りであれば、正しい値を代入します:
// 文字列ではなく整数が必要だった場合
let x: i32 = 42; // OK
修正3: 明示的に変換する
型を変換する必要がある場合、Rustは明示的な変換を要求します。状況に合ったものを選んでください:
// &str → String
let s: String = "hello".to_string();
let s: String = String::from("hello");
// String → &str
let owned = String::from("hello");
let borrowed: &str = &owned;
// i64 → i32(値が2_147_483_647を超える場合は切り捨て)
let big: i64 = 100;
let small: i32 = big as i32;
// String → 整数
let n: i32 = "42".parse().unwrap();
// より安全な書き方 — 失敗時の理由が分かる:
let n: i32 = "42".parse().expect("not a valid number");
よくあるケース
関数の戻り値の型不一致
末尾のセミコロンがあると、戻り値の型が暗黙的に () に変わります。セミコロンを削除してください:
// error: expected i32, found ()
fn get_value() -> i32 {
let x = 42;
// xを返し忘れている — またはxの後にセミコロンが付いている
}
// 修正: 最後の式のセミコロンを削除する
fn get_value() -> i32 {
let x = 42;
x // 暗黙のreturn — セミコロンなし
}
整数型の混在
Vec::len() は i32 ではなく usize を返します。初心者がよくつまずくポイントです:
fn print_length(v: &Vec<i32>) {
let len: i32 = v.len(); // error: expected i32, found usize
}
// 修正: 正しい型を使うか、明示的にキャストする
fn print_length(v: &Vec<i32>) {
let len: usize = v.len(); // 正しい型
let len2: i32 = v.len() as i32; // 明示的なキャスト(小さいVecなら安全)
}
Optionのアンラップ
Iterator::next() は T ではなく Option<T> を返します。Optionを伝播させるか、フォールバックを用意してください:
fn first_char(s: &str) -> char {
s.chars().next() // error: expected char, found Option<char>
}
// 方法1: 戻り値の型をOptionに変更して伝播させる
fn first_char(s: &str) -> Option<char> {
s.chars().next()
}
// 方法2: 空文字列のデフォルト値でアンラップする
fn first_char(s: &str) -> char {
s.chars().next().unwrap_or('\0')
}
構造体フィールドの型不一致
struct User {
age: u32,
}
// error: expected u32, found i32
let user = User { age: -1i32 };
// 修正: 有効なu32の値を使う
let user = User { age: 25u32 };
エラーメッセージの読み方
Rustのコンパイラは正確な場所と関係する両方の型を表示します。読み方は次の通りです:
error[E0308]: mismatched types
--> src/main.rs:5:18
|
5 | let x: i32 = "hello";
| --- ^^^^^^^ expected `i32`, found `&str`
| |
| expected due to this type annotation
src/main.rs:5:18— ファイル名、5行目、18列目(型不一致の場所)i32の下の---— 宣言された型"hello"の下の^^^^^^^— 問題のある値expected X, found Y— Xはコンテキストが要求する型、Yは実際に渡した型
Expected(期待された型) はアノテーション、関数シグネチャ、構造体フィールドなどのコンテキストが要求する型です。Found(実際の型) は記述したコードの実際の型です。どちらか一方をもう一方に合わせて修正してください。
型推論に任せる
関数の戻り値の型が分からない場合は、アノテーションを省略してRustに推論させましょう:
// Rustに型を推論させる
let x = some_function();
// 実際の型を知りたい場合は、意図的にエラーを起こす:
let _: () = some_function(); // Rustが実際の型を教えてくれる
エラーには expected (), found SomeType と表示され、実際に推論された型が分かります。IDEなしで素早く型を調べられる便利なテクニックです。
動作確認
cargo build を実行します。ビルドが成功した場合の出力は次の通りです:
Compiling myproject v0.1.0 (/path/to/myproject)
Finished dev [unoptimized + debuginfo] target(s) in 0.42s
出力に error[E0308] が含まれていなければ修正完了です。テストがある場合は合わせて実行しましょう:
cargo test

