Rustのエラー E0530: match bindings cannot shadow tuple variants(バリアント名は変数にできない)
E0530 は、パターンの中の名前が、もう別のものに使われている、という意味のエラーです。Circle のようなただの名前を、Rust がふつうなら新しい変数を作る場所に書きました。ところが Circle は、このスコープではすでに別のもの(タプルバリアント、タプル構造体、または static)を指しています。それを新しい変数の陰にこっそり隠してしまうのは、ほぼ間違いなく書いた人の意図ではないので、Rust はこれを拒みます。典型的なのは、use Shape::*; のあとの match の腕 Circle => です。直し方はたいてい4文字だけで、Circle(..) と書けば済みます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0530]: match bindings cannot shadow tuple variants --> src/main.rs:10:9 | 6 | use Shape::*; | -------- the tuple variant `Circle` is imported here...10 | Circle => "circle", // ❌ `Circle` holds a value | ^^^^^^ | | | cannot be named the same as a tuple variant | help: try specify the pattern arguments: `Circle(..)`「match bindings cannot shadow tuple variants」は「match の束縛でタプルバリアントを覆い隠す(シャドーイングする)ことはできない」という意味です。help は「パターンの引数を書いてみてください:Circle(..)」と言っています。
このエラーが出るのは、次のプログラムです。
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle => "circle", // ❌ `Circle` holds a value Square(_) => "square", }}
fn main() { println!("{}", name(&Circle(1.0)));}コメントは「Circle は値を持っている」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”^^^ は10行目の Circle を指し、6行目の --- はその名前がどこから来たのかを示しています(「the tuple variant Circle is imported here」=タプルバリアント Circle はここでインポートされた)。use Shape::*; が、バリアント Shape::Circle をスコープに持ち込んだのです。
パターンの中では、x や other のようなただの名前は、新しい変数を作り、どんな値にもマッチします。だから Circle => には、2つの意味がありえます。
- 「バリアント
Circleにマッチする」。ただしCircleはf64を持っているので、正しいパターンにはCircle(_)やCircle(..)のようにかっこが必要です。 - 「何にでもマッチして、それを
Circleと呼ぶ」。バリアントを隠してしまう新しい変数です。
Rust は推測しません。見出しの最後で、何という種類の名前とぶつかったのかがわかり、最初の言葉で、どこでぶつかったのかがわかります。
match bindings cannot shadow ...:matchの腕の中let bindings cannot shadow ...:letやif letの中function parameters cannot shadow ...:関数の引数リストの中
そして最後は、tuple variants(タプルバリアント)、tuple structs(タプル構造体)、statics(static)のどれかになります。
飼い犬に「先生」と名付けるようなものです。病院の待合室で誰かが「先生!」と呼ぶたびに、誰のことなのかわからなくなってしまいます。
Rust がこうする理由
Section titled “Rust がこうする理由”このルールがなければ、Circle => は Circle という名前の新しい変数になります。それはすべての値にマッチするので、そのあとの腕はどれも決して実行されない死んだコードになります。プログラムはコンパイルできてしまい、正方形にも「circle」と表示します。正しそうに見えるコードの陰に隠れる、たちの悪いバグです。
そこで Rust は、新しい変数がタプルバリアント、タプル構造体、static の名前を取ろうとしたときは、いつでもエラーにします。かっこを付けて意図をはっきり書くか、別の名前を選ぶかのどちらかです。None のようなユニットバリアントや定数(const)は別です。これらはそれだけで正しいパターンなので、Rust は「この値にマッチする」と読みます。詳しくはパターンマッチングと列挙型を見てください。
直し方1:(..) か (_) を付けて、バリアントにマッチさせる
Section titled “直し方1:(..) か (_) を付けて、バリアントにマッチさせる”メッセージが tuple variants や tuple structs で終わっているときは、これを選びます。いちばんよくあるケースです。意図していたのはバリアントなので、rustc の help のとおりにかっこを付けます。Shape::Circle(_) のように完全なパスで書くと、さらにわかりやすくなります。
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle(..) => "circle", // ✅ バリアント。中の値は何でもいい Square(_) => "square", }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ 完全なパスで書き、値も使う Shape::Square(side) => side * side, }}
fn main() { let shapes = [Circle(1.0), Square(2.0)]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); }}実行結果:
circle: 3.14square: 4.00.. は「中身が何であっても」という意味です。あとでバリアントが持つ値が増えても、そのまま動き続けます。詳しくは_ と .. で一部を無視するを見てください。
直し方2:変数の名前を変える
Section titled “直し方2:変数の名前を変える”本当に新しい変数が欲しくて、その名前がたまたま型と同じだっただけのときは、これを選びます。変数に型と同じ名前を付けたときの let や関数の引数で、よく起こります。
error[E0530]: let bindings cannot shadow tuple structs --> src/main.rs:4:9 |1 | struct Meters(f64); | ------------------- the tuple struct `Meters` is defined here...4 | let Meters = 5.0; // ❌ `Meters` is a tuple struct | ^^^^^^ cannot be named the same as a tuple struct「let bindings cannot shadow tuple structs」は「let の束縛でタプル構造体を覆い隠すことはできない」、「cannot be named the same as a tuple struct」は「タプル構造体と同じ名前は付けられない」という意味です。
このエラーが出るプログラムです。
struct Meters(f64);
fn main() { let Meters = 5.0; // ❌ `Meters` is a tuple struct println!("{}", Meters);}Rust の名前の付け方のスタイルが、この問題を解決してくれます。型やバリアントは CamelCase、変数は snake_case です。小文字の名前を使えば、ぶつからなくなります。
struct Meters(f64);
fn total(meters: &[Meters]) -> f64 { meters.iter().map(|m| m.0).sum()}
fn main() { let meters = 5.0; // ✅ 変数名は小文字にする println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ またはタプル構造体を分解する println!("身長: {} m", height);
println!("合計: {} m", total(&[Meters(2.0), Meters(3.5)]));}実行結果:
5 m身長: 1.8 m合計: 5.5 m関数の引数でも同じです。fn show(Point: i32) は function parameters cannot shadow tuple structs(関数の引数でタプル構造体を覆い隠すことはできない)になり、fn show(point: i32) にすれば直ります。詳しくは名前の付け方のルールを見てください。
直し方3:static の代わりに const(またはマッチガード)を使う
Section titled “直し方3:static の代わりに const(またはマッチガード)を使う”メッセージが statics で終わっているときは、これを選びます。たぶん、決まった値と比べたかったのでしょう。static はパターンに使えませんが、const なら使えます。
error[E0530]: match bindings cannot shadow statics --> src/main.rs:5:9 |1 | static LIMIT: u32 = 100; | ------------------------ the static `LIMIT` is defined here...5 | LIMIT => "full", // ❌ a static can't be a pattern | ^^^^^ cannot be named the same as a static「match bindings cannot shadow statics」は「match の束縛で static を覆い隠すことはできない」という意味です。
このエラーが出るプログラムです(コメントは「static はパターンにできない」という意味です)。
static LIMIT: u32 = 100;
fn status(users: u32) -> &'static str { match users { LIMIT => "full", // ❌ a static can't be a pattern _ => "open", }}
fn main() { println!("{}", status(100));}static を const に変えましょう。どうしても static のままにしておく必要があるとき(たとえば、ほかのコードがそのアドレスを使っているとき)は、値を名前に束縛して、マッチガードで比べます。
const LIMIT: u32 = 100; // ✅ const はパターンとして使えるstatic MAX_USERS: u32 = 500; // static は static のまま
fn status(users: u32) -> &'static str { match users { LIMIT => "full", _ => "open", }}
fn premium_status(users: u32) -> &'static str { match users { n if n >= MAX_USERS => "full", // ✅ static はガードで比べる _ => "open", }}
fn main() { println!("{}", status(100)); println!("{}", status(42)); println!("{}", premium_status(500));}実行結果:
fullopenfullただの数値なら、static が必要になることはめったにありません。ふつうは const を選びます。詳しくは定数を見てください。
よく出会う場面
Section titled “よく出会う場面”かっこのない Ok => や Some =>。 Ok、Err、Some はプレリュードにあるタプルバリアントなので、match result { Ok => ... } は E0530 になり、try specify the pattern arguments: `Ok(..)` という help が付きます。直し方:Ok(_) => か Ok(value) => と書きます。
if let の中。 if let Some(Some) = x は、中の値を Some と名付けようとするので、let bindings cannot shadow tuple variants になります。直し方:if let Some(inner) = x のように小文字の名前にします。
完全なパスで書くと E0532 になる。 Shape::Circle => は新しい変数にはなりえない(変数名に :: は入らない)ので、rustc は E0532「expected unit struct, unit variant or constant, found tuple variant」(ユニット構造体、ユニットバリアント、定数を期待したのに、タプルバリアントが見つかった)を出します。直し方は同じで、(_) か (..) を付けます。
ユニット構造体の名前を使った let は E0308 になる。 struct Guest; があると、let Guest = "Ana"; という行は変数をまったく作りません。rustc は Guest をユニット構造体として読み、E0308(mismatched types、型の不一致)を出して、`Guest` is interpreted as a unit struct, not a new binding(Guest は新しい束縛ではなく、ユニット構造体として解釈される)と言います。直し方:let guest = "Ana"; のように変数名を変えます。
関連するエラー
Section titled “関連するエラー”- E0532:expected unit struct, unit variant or constant, found tuple variant。
Shape::Circle =>のように、パスで書いたときの同じ間違いです。 - E0533:expected unit struct, unit variant or constant, found struct variant。名前付きフィールドを持つバリアントを、
{ .. }なしで使った。 - E0004:non-exhaustive patterns。腕を直したあとも、
matchはすべてのバリアントを網羅しなければなりません。 - E0308:mismatched types。ユニット構造体の名前を使った
letで出るエラーです。 - E0425:cannot find value in this scope。逆の問題で、その名前がまったく存在しない。
- コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. Circle(f64) がバリアントで、use Shape::*; を書いたあとです。コンパイルできる match の腕はどれですか?
2. let Meters = 5.0; に対して、rustc が「let bindings cannot shadow tuple structs」と言いました。いちばん簡単な直し方はどれですか?
3. static LIMIT: u32 = 100; は match のパターンに使えません。パターンに使えるのはどれですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0530 — Rust error codes index(英語):このエラーの公式の説明です。
(_)を書き忘れた例と、staticとconstの例が載っています。 - パターン記法 — The Rust Programming Language 日本語版:名前付き変数へのマッチ、列挙型の分解、
_と..で値を無視する方法です。 - Identifier patterns — The Rust Reference(英語):パターンの中の名前が、新しい変数になるのか、すでにあるものを指すのかを決める、正確なルールです。
- 列挙型 — Rust By Example 日本語版:ユニットバリアントとタプルバリアントへのマッチを、並べて見られます。
- Static items — The Rust Reference(英語):
staticがconstとどう違うか(使う場所ごとにコピーされる値ではなく、メモリ上の決まった1か所)の説明です。