Rustのエラー E0689: can't call method on ambiguous numeric type(数値の型が決まっていない)
E0689 は、数値に対してメソッドを呼んだけれど、それがどの種類の数値なのか Rust にはまだわからない、という意味のエラーです。2 は i32 かもしれないし、u8 や u64 かもしれません。そして、それぞれの型が自分の pow メソッドを持っています。どれのつもりなのかを Rust に教えてあげればいいだけです。たいていは 2_i32 や let x: f64 のように、数文字を足せば済みます。どこに書けばいいかも rustc が教えてくれます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> src/main.rs:2:16 |2 | let kb = 2.pow(10); // ❌ which kind of integer is `2`? | ^^^ |help: you must specify a concrete type for this numeric value, like `i32` |2 | let kb = 2_i32.pow(10); // ❌ which kind of integer is `2`? | ++++「can’t call method pow on ambiguous numeric type {integer}」は「型があいまいな数値 {integer} に対して、メソッド pow を呼べない」という意味です。help は「この数値には i32 のような具体的な型を指定してください」と言っていて、2_i32 という書き方を見せてくれています。
このエラーが出るのは、次のプログラムです。
fn main() { let kb = 2.pow(10); // ❌ which kind of integer is `2`? println!("{}", kb);}コメントは「2 はどの種類の整数?」という意味です(エラーになる例なので、コードはそのままにしています)。
小数でも同じことが起こります。次の例では、数値をいったん変数に入れているので、rustc は代わりに変数の型を提案してきます。
error[E0689]: can't call method `sqrt` on ambiguous numeric type `{float}` --> src/main.rs:3:18 |3 | let root = x.sqrt(); // ❌ is `x` an f32 or an f64? | ^^^^ |help: you must specify a type for this binding, like `f32` |2 | let x: f32 = 2.0; | +++++ここでの help は「この変数には f32 のような型を指定してください」という意味です。
fn main() { let x = 2.0; let root = x.sqrt(); // ❌ is `x` an f32 or an f64? println!("{}", root);}コメントは「x は f32? それとも f64?」という意味です。
エラーの意味
Section titled “エラーの意味”{integer} と {float} は、rustc 流の「正確な型をまだ決めていない数値」という言い方です。{integer} は何かの整数型(i8〜i128、u8〜u128、isize、usize)で、{float} は f32 か f64 です。
^^^ はメソッドの名前を指しています。メソッドは型に属しています。i32::pow、u64::pow、f32::sqrt、f64::sqrt というふうに、別々にあるのです。結果も違います(i32 には 2 の 40 乗が入りませんが、u64 には入ります)。どれかを呼ぶには、Rust はコードのその地点で型を知っていなければなりません。ところが、ここではまだわかっていないのです。
お店の人に「2つでいくらですか?」と聞くようなものです。2つって、何が? りんご2個とテレビ2台では、値段がまるで違います。「りんごを2個」と言えば、答えはすぐに出ます。
Rust がこうする理由
Section titled “Rust がこうする理由”Rust には、数値のデフォルトの型があります。ほかに何も決め手がなければ、整数は i32 に、小数は f64 になります。詳しくは整数と浮動小数点数(小数)を見てください。
ただし、このデフォルトは最後の手段です。Rust はまず関数の残りの部分を読んで、ほかの何かが型を決めていないかを確かめます。たとえば、その数値を u8 を受け取る関数に渡している、といった場合です。i32 や f64 に落ち着くのは、本当に最後の最後です。メソッドの呼び出しは、そこまで待てません。引数と結果の型をチェックする前に、どの pow を呼ぶのかを知る必要があるからです。だから Rust は、当てずっぽうで決めずに、いったん止まってあなたに聞くのです。
これは、あとに続くコードは助けにならない、ということでもあります。let y: u64 = x.pow(10); と書いても E0689 になります。Rust は pow を呼ぶ前に x の型を決めなければならないのに、u64 が付いているのは結果のほうだけだからです。助けになるのは、メソッドを呼ぶ前に数値に型を付けることです。
直し方1:数値に型の接尾辞を付ける
Section titled “直し方1:数値に型の接尾辞を付ける”2.pow(10) や 2.0.sqrt() のように、数値リテラルに直接メソッドを呼んでいるときは、これを選びます。数値のすぐあとに型を書きましょう。_ はなくてもかまいません。読みやすくするためだけのもので、2_i32 と 2i32 は同じです。
小数の場合、rustc は f32 を提案しますが、Rust のデフォルトは f64 で、こちらのほうが精度も高いです。メモリを節約したい理由がなければ、f64 を選びましょう。
fn main() { let kb = 2_i32.pow(10); // ✅ i32 let big = 2_u64.pow(40); // ✅ u64:2^40 は i32 に収まらない let root = 2.0_f64.sqrt(); // ✅ f64 let dist = (-7_i32).abs(); // ✅ `-` がメソッド呼び出しより先に来るように、かっこで囲む
println!("2^10 = {}", kb); println!("2^40 = {}", big); println!("sqrt(2) = {}", root); println!("|-7| = {}", dist);}実行結果:
2^10 = 10242^40 = 1099511627776sqrt(2) = 1.4142135623730951|-7| = 7結果が収まるだけの大きさの型を選びましょう。2_i32.pow(40) はコンパイルできますが、オーバーフローして、デバッグビルドではパニックします。詳しくは整数のオーバーフローを見てください。
直し方2:変数に型を付ける
Section titled “直し方2:変数に型を付ける”let x = 2.0; のように、数値をいったん変数に入れているときは、これを選びます。rustc の help: の行が提案しているのも、この方法です。変数名のあとに : 型 を付けましょう。
fn main() { let x: f64 = 2.0; // ✅ これで x は f64 println!("{:.3}", x.sqrt());
let side: f64 = 3.5; println!("面積 = {}", side.powi(2));
let temperature: i32 = -5; println!("0度から{}度離れている", temperature.abs());
let base: u64 = 2; let y = base.pow(10); // y も u64 println!("{}", y);}実行結果:
1.414面積 = 12.250度から5度離れている1024値のほうに接尾辞を付けて let x = 2.0_f64; と書いても同じように動きます。読みやすいと思うほうを使いましょう。詳しくは型注釈を見てください。
直し方3:ループ変数やクロージャの引数に型を付ける
Section titled “直し方3:ループ変数やクロージャの引数に型を付ける”for i in 1..=3 や (1..=5).map(|n| ...) のように、数値が範囲から来ているときは、これを選びます。変数 i や n の型は {integer} で、型注釈を付けられる let がありません。rustc はその変数を指してくれます。
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> src/main.rs:3:26 |2 | for i in 1..=3 { | - you must specify a type for this binding, like `i32`3 | println!("{}", i.pow(2)); | ^^^you must specify a type for this binding, like `i32` は「この変数には i32 のような型を指定してください」という意味です。
範囲の片方の端に接尾辞を付けるか、クロージャの引数に型を付けましょう。
fn main() { for i in 1..=3_u32 { // ✅ これで範囲全体が u32 になる println!("{}の2乗は{}", i, i.pow(2)); }
// 範囲に接尾辞を付けるか…… let total: u32 = (1..=5_u32).map(|n| n.pow(2)).sum(); // ……クロージャの引数に型を付ける let total2: u32 = (1..=5).map(|n: u32| n.pow(2)).sum(); println!("2乗の合計: {} と {}", total, total2);}実行結果:
1の2乗は12の2乗は43の2乗は92乗の合計: 55 と 55let total: u32 = ... だけでは足りないことに注目してください。rustc は .sum() にたどり着く前に、クロージャの中の n の型を知る必要があるのです。範囲に接尾辞を1つ付ければ、すべて解決します。
よく出会う場面
Section titled “よく出会う場面”負の数に abs()。 let x = -5; x.abs() は can't call method `abs` on ambiguous numeric type `{integer}` になります。直し方:let x: i32 = -5;。リテラルに接尾辞を付けるときは気をつけましょう。-5_i32.abs() は -(5_i32.abs()) という意味なので、結果は -5 です。(-5_i32).abs() のようにかっこで囲みましょう。
main やテストでのちょっとした計算。 let area = 3.14 * r * r; は問題なく動きます。* はメソッドではなく演算子だからです。エラーが出るのは、.sqrt()、.round()、.powi() のようなメソッドを呼んだときだけです。直し方:let r: f64 = 2.0;。
数値の Vec。 let nums = vec![1, 2, 3]; のとき、nums.iter().map(|n| n.pow(2)) は別のコード、E0599 の no method named `pow` found for reference `&{integer}`(参照 &{integer} に pow という名前のメソッドはない)になります。ここでは n が参照だからです。直し方は同じです:vec![1_i32, 2, 3] か let nums: Vec<i32> = vec![1, 2, 3]; と書きます。
関連するエラー
Section titled “関連するエラー”- E0282: type annotations needed:
Vec::new()や.collect()のように、Rust がそもそも型を推論できない。型の名前を書く、という直し方の考え方は同じです。 - E0610: primitive type doesn’t have fields:
x.abs()ではなくx.absのように、{integer}に()なしで.somethingを付けた。 - E0599: no method named x found:型はわかっているけれど、そのメソッドがない。あるいは(上のように)
{integer}への参照になっている。 - E0308: mismatched types:選んだ型が、その数値を使う場所と合わないときに、次に出るかもしれないエラーです。
- コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. コンパイルできるのはどの行ですか?
2. ほかに何も決め手がないとき、Rust は 7 と 7.0 にどの型を付けますか?
3. for i in 0..10 { println!("{}", i.pow(2)); } が E0689 になります。いちばん簡単な直し方はどれですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0689 — Rust error codes index(英語):このエラーの公式の説明です。
- データ型 — The Rust Programming Language 日本語版:整数型と浮動小数点型、
57u8のような接尾辞付きの数値リテラル、デフォルトのi32とf64を説明している章です。 - リテラルとオペレータ — Rust By Example 日本語版:
1u32や1.0f64のような接尾辞で型が決まるしくみです。 - Integer literal expressions — The Rust Reference(英語):
i32への落ち着き方も含めた、リテラルの型が決まる正確なルールです。 f64::sqrt— 標準ライブラリのドキュメント(英語):型がわかっている必要がある浮動小数点数のメソッド(sqrt、powi、roundなど)です。