コンテンツにスキップ

Rustのエラー E0530: match bindings cannot shadow tuple variants(バリアント名は変数にできない)

E0530 は、パターンの中の名前が、もう別のものに使われている、という意味のエラーです。Circle のようなただの名前を、Rust がふつうなら新しい変数を作る場所に書きました。ところが Circle は、このスコープではすでに別のもの(タプルバリアント、タプル構造体、または static)を指しています。それを新しい変数の陰にこっそり隠してしまうのは、ほぼ間違いなく書いた人の意図ではないので、Rust はこれを拒みます。典型的なのは、use Shape::*; のあとの match の腕 Circle => です。直し方はたいてい4文字だけで、Circle(..) と書けば済みます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。

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 は値を持っている」という意味です(エラーになる例なので、コードはそのままにしています)。

^^^ は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)のどれかになります。

飼い犬に「先生」と名付けるようなものです。病院の待合室で誰かが「先生!」と呼ぶたびに、誰のことなのかわからなくなってしまいます。

このルールがなければ、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.14
square: 4.00
▶ 実際に試してみよう

.. は「中身が何であっても」という意味です。あとでバリアントが持つ値が増えても、そのまま動き続けます。詳しくは_ と .. で一部を無視するを見てください。

本当に新しい変数が欲しくて、その名前がたまたま型と同じだっただけのときは、これを選びます。変数に型と同じ名前を付けたときの 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));
}

実行結果:

full
open
full
▶ 実際に試してみよう

ただの数値なら、static が必要になることはめったにありません。ふつうは const を選びます。詳しくは定数を見てください。

かっこのない 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"; のように変数名を変えます。

  • 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。逆の問題で、その名前がまったく存在しない。
  • コンパイルエラーの一覧:エラー解説ページの全リストです。

理解度チェック

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