Rustのエラー E0610: primitive type doesn't have fields(数値にフィールドはない)
E0610 は、something.field と書いたけれど、something はただの数値(または bool や char)で、そういう型にはフィールドがひとつもない、という意味のエラーです。ほとんどの場合、変数が思っている型になっていないことを表しています。構造体から数値をもう取り出していた、関数が構造体ではなく数値を返していた、.0 を1つ多く書いていた、などです。メッセージには Rust から見えている正確な型が書かれているので、直し方まであと一歩です。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> src/main.rs:3:22 |3 | println!("{}", x.value); // ❌ x は数値なので、`value` フィールドはない | ^^^^^「{integer} is a primitive type and therefore doesn’t have fields」は「{integer} はプリミティブ型(組み込みの基本型)なので、フィールドを持たない」という意味です。
このエラーが出るのは、次のプログラムです。
fn main() { let x = 5; println!("{}", x.value); // ❌ x は数値なので、`value` フィールドはない}エラーの意味
Section titled “エラーの意味”バッククォートの中の型は、Rust がその変数の型だと考えているものです。ここでは `{integer}` で、「何かの整数。どの種類かはまだ決めていない」という意味です(ほかに何も決め手がなければ、Rust はあとで i32 を選びます)。小数なら `{float}`、ほかにも u32、usize、f64、bool、char のような具体的な型が表示されることもあります。
^^^^^ は、ドットのあとの名前を指しています。Rust は「value のつづりが違う」と言っているのではありません。「数値には、どんな名前でもフィールドはない」と言っているのです。
ですから、考えるべきなのは「なぜこの変数は数値なのか」です。「5 の値札」を見せてと頼むようなものです。商品には値札がありますが、5 はただの数です。
Rust がこうする理由
Section titled “Rust がこうする理由”i32、u32、f64、bool、char のようなプリミティブ型は、言語に組み込まれた単一の値です。構造体ではないので、ドットと名前で取り出せる中身はありません。詳しくはデータ型を見てください。
ただし、メソッドは持っています。x.abs()、x.pow(2)、price.round()、c.is_alphabetic() などです。メソッドは () を付けて呼びます。フィールドは構造体の中にしまってあるデータで、フィールドを持てるのは構造体、タプル、共用体(union)だけです。
Rust はすべての .field をコンパイル時にチェックするので、この取り違えが実行時のクラッシュや、知らないうちに undefined になる、といった問題になることはありません。すぐに、ぴったりその行で気づけます。
直し方1:数値をそのまま使う
Section titled “直し方1:数値をそのまま使う”構造体からフィールドをもう取り出しているときは、これを選びます。let count = counter.value; のあと、count は数値そのものなので、count.value は u32 のフィールドを求めていることになります。
error[E0610]: `u32` is a primitive type and therefore doesn't have fields --> src/main.rs:8:26 |8 | println!("{}", count.value); | ^^^^^数値をそのまま使うか、構造体に戻ってそこからフィールドを読みましょう。
struct Counter { value: u32,}
fn main() { let mut counter = Counter { value: 0 }; counter.value += 3;
let count = counter.value; // count はもうただの u32 println!("{}", count); // ✅ 数値そのものを使う println!("{}", counter.value); // ✅ または構造体からフィールドを読む}実行結果:
33変数の型がわからないときは、エディタで変数にマウスを乗せてみましょう(rust-analyzer を使います。Rustの開発ツールを見てください)。または、一時的に let _: () = count; と書いてみます。rustc が expected `()`, found `usize`(() を期待したが usize だった)と答えて、本当の型を教えてくれます。確認したら、その行は消してください。
直し方2:数値ではなく構造体を返す・しまう
Section titled “直し方2:数値ではなく構造体を返す・しまう”値が関数やコレクションから来ていて、構造体だと思っていたときは、これを選びます。よくあるのは次の2つです。
fn find_order() -> u32のような関数が注文の ID を返していて、orderがu32なのでorder.totalが失敗する。HashMap<&str, u32>にスコアだけをしまっていて、値がどれもPlayerではなくu32なので、scores["ana"].scoreが失敗する。
本当にほしいものは何かを決めましょう。複数のデータが必要なら、戻り値の型や値の型を構造体に変えます。
use std::collections::HashMap;
struct Order { id: u32, total: u32, // セント単位}
// 数値だけでなく、Order をまるごと返すfn new_order(id: u32, total: u32) -> Order { Order { id, total }}
struct Player { score: u32, level: u8,}
fn main() { let order = new_order(7, 1999); println!("注文{}は{}セントです", order.id, order.total);
// マップにはスコアだけでなく、Player をまるごとしまう let mut players: HashMap<&str, Player> = HashMap::new(); players.insert("ana", Player { score: 10, level: 2 });
let ana = &players["ana"]; println!("ana: スコア{}、レベル{}", ana.score, ana.level);}実行結果:
注文7は1999セントですana: スコア10、レベル2必要なのが数値だけなら、u32 のままにして、.field の部分を消すだけで大丈夫です。詳しくは構造体とHashMapを見てください。
直し方3:余分な .0 を消す
Section titled “直し方3:余分な .0 を消す”エラーが .0 や .1 を指しているときは、これを選びます。タプルとタプル構造体は、フィールドを位置で表します。そのため、つい1段深く入りすぎてしまいがちです。let x = point.0; のあと、x はもう数値なので、x.0 は `{integer}` is a primitive type になります。struct Meters(u32); のようなラッパーでも同じです。1つ目の .0 で u32 を取り出せますが、2つ目の .0 は失敗します。
struct Meters(u32);
fn main() { let point = (3, 4); let x = point.0; // x はもう数値の 3 println!("x = {}", x); // x.0 ではない
let m = Meters(42); println!("{} m", m.0); // .0 を1つ付けると、タプル構造体から u32 を取り出せる
let line = ((0, 0), (3, 4)); // 入れ子のタプル:1段ごとに位置を1つ println!("終点の y = {}", line.1.1);}実行結果:
x = 342 m終点の y = 4段の数を数えましょう。.0 や .1 を1つ書くたびに、タプルの中に1段入ります。数値にたどり着いたら、そこで止まります。位置がわかりにくくなってきたら、代わりに構造体で名前を付けましょう。詳しくは位置で要素を取り出すとタプルと構造体の使い分けを見てください。
よく出会う場面
Section titled “よく出会う場面”() のないメソッド。 f64 に price.round、i32 に x.abs と書いたときは、E0610 ではなく E0615「attempted to take value of method」(メソッドを値として取り出そうとした)になります。これらの名前はメソッドだからです。直し方:price.round()、x.abs()。ひとつ意外な点があります。型がまだ {integer} のまま(let x = -5; など)だと、x.abs でも E0610 になり、x.abs() と書くと今度は E0689「can’t call method abs on ambiguous numeric type {integer}」(あいまいな数値型 {integer} ではメソッド abs を呼べない)になります。let x: i32 = -5; のように型を決めれば、x.abs() が使えます。
数値への参照。 変数が u32 ではなく &u32 だと、エラーコードは E0609 の no field `value` on type `&u32` に変わります。よくあるのは for (name, score) in &players のようなループで、score が &i32 なので、score.1 が no field `1` on type `&{integer}` になる場面です。原因も直し方も同じで、score はもう数値です。
len() や count() の結果。 let len = scores.len(); で得られるのは usize なので、len.count は `usize` is a primitive type で失敗します。直し方:len をそのまま使います。
単位付きの数値。 price.cents や distance.meters と書きたいなら、小さな構造体を作りましょう。struct Price { cents: u64 } です。こうすれば price.cents が使えて、値段とほかの数値を取り違えることも型が防いでくれます。詳しくは構造体を見てください。
関連するエラー
Section titled “関連するエラー”- E0609: no field
xon typeT:その型に、その名前のフィールドがない。&u32のような参照のときは、E0610 ではなくこちらが出ます。 - E0615: attempted to take value of method:
price.round()ではなくprice.roundと書いた。 E0689: can't call method on ambiguous numeric type:型がまだ決まっていない数値でメソッドを呼んだ。i32のような型を付けましょう。- E0599: no method named x found:メソッド版のエラーです。たとえば、数値が持っていないメソッドを呼んだとき。
- E0308: mismatched types:関数が数値を返しているのに構造体を期待していたとき、E0610 と一緒によく出ます。
- コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. let total = cart.total;(total は u32 のフィールド)のあとで total.amount と書くと、どうなりますか?
2. メッセージの {integer} はどういう意味ですか?
3. let x = point.0; のあとで x.0 と書くと E0610 になります。どう直しますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0610 — Rust error codes index(英語):このエラーの公式の説明です。
- データ型 — The Rust Programming Language 日本語版:スカラー型(整数、浮動小数点数、
bool、char)と複合型(タプル、配列)を説明している章です。 - 構造体を定義し、インスタンス化する — The Rust Programming Language 日本語版:章の後半で、
Meters(u32)のようなタプル構造体と、それに.0を使うしくみを説明しています。 - 基本データ型 — Rust By Example 日本語版:組み込みの型を、実行できる例で紹介しています。
i32— 標準ライブラリのドキュメント(英語):整数が持っているメソッドの一覧です(どれも()を付けて呼ぶことがわかります)。