Lewati ke konten

Error Rust E0164: expected tuple struct or tuple variant, found struct variant

E0164 artinya: kamu menulis tanda kurung di sebuah pattern, seperti Shape::Circle(r), setelah nama yang tidak menerima nilai dalam tanda kurung. Di Rust versi sekarang, kamu akan menemuinya dalam tiga situasi: varian enum dengan field bernama (Circle { radius: f64 }) yang dicocokkan seolah-olah varian tuple, fungsi asosiasi seperti Celsius::new(d) yang dipakai sebagai pattern, dan konstanta asosiasi seperti Volume::MAX(_) dengan tanda kurung di belakangnya. Masing-masing punya perbaikan yang singkat dan jelas. (Halaman ini bagian dari Penjelasan error compiler Rust.)

error[E0164]: expected tuple struct or tuple variant, found struct variant `Shape::Circle`
--> src/main.rs:8:9
|
8 | Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` punya field bernama
| ^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
help: the struct variant's field is being ignored
|
8 - Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` punya field bernama
8 + Shape::Circle { radius: _ } => 3.14 * r * r, // ❌ `Circle` punya field bernama
|

Ini program yang menghasilkan error tersebut:

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` punya field bernama
Shape::Square { side } => side * side,
}
}
fn main() {
println!("{}", area(&Shape::Square { side: 2.0 }));
}

^^^ menutupi seluruh pattern Shape::Circle(r), dan labelnya menyebut apa yang diharapkan Rust di situ: “a tuple struct or tuple variant” (struct tuple atau varian tuple). Hanya dua jenis hal itu yang ditulis dengan tanda kurung di sebuah pattern, karena hanya mereka yang menyimpan nilai berdasarkan posisi, seperti Some(x) atau Meters(m).

Shape::Circle adalah varian struct. Nilainya punya nama, radius, dan field bernama dicocokkan dengan kurung kurawal: Shape::Circle { radius }.

Hati-hati dengan help: di sini. Ia menyarankan Shape::Circle { radius: _ }, yang memang memperbaiki pattern-nya tapi mengabaikan radiusnya. Cabang kita memakai r, jadi kalau kamu menyalin sarannya begitu saja, kamu mendapat error baru, E0425 cannot find value `r` in this scope. Kalau kamu butuh nilainya, beri nama di dalam kurung kurawal, seperti di Perbaikan 1.

Ini seperti formulir dengan kotak berlabel, “Lebar: … Tinggi: …”, lalu kamu menulis “3, 4” di sebelah judulnya. Angkanya mungkin benar, tapi formulirnya ingin setiap angka ada di kotak berlabelnya masing-masing.

Sebuah pattern harus terlihat seperti nilai yang dicocokkannya. Rust punya dua cara untuk menyimpan data, dan masing-masing punya pattern sendiri (lihat Enum bisa menyimpan data):

Didefinisikan sebagai Dibuat dengan Dicocokkan dengan
Circle(f64) (varian tuple) Shape::Circle(1.0) Shape::Circle(r)
Circle { radius: f64 } (varian struct) Shape::Circle { radius: 1.0 } Shape::Circle { radius }

Field bernama dicocokkan berdasarkan nama, bukan posisi, jadi urutan di pattern tidak penting, dan menambah field nanti tidak diam-diam menggeser field lainnya. Mencampur kedua gaya itu ditolak, jadi tidak pernah ada keraguan nilai mana masuk ke mana.

Pattern juga diperiksa saat kompilasi, jadi pattern tidak bisa menjalankan kode. Itulah sebabnya nama fungsi yang diikuti (d) juga tidak bisa menjadi pattern, bahkan kalau fungsi itu membuat persis nilai yang sedang kamu cocokkan. Selengkapnya di Pattern Matching.

Perbaikan 1: Pakai kurung kurawal dengan nama field-nya

Section titled “Perbaikan 1: Pakai kurung kurawal dengan nama field-nya”

Pilih ini kalau pesannya bilang found struct variant, yaitu E0164 yang paling sering muncul. Tulis nama field-nya (Rust lalu membuat variabel dengan nama itu), field: nama_baru untuk memilih nama lain, atau { .. } untuk mengabaikan semua field:

enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ nama field di dalam kurung kurawal
Shape::Rect { w: width, h: height } => width * height, // ✅ field: nama baru
}
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "lingkaran", // ✅ "lingkaran apa saja"
Shape::Rect { .. } => "persegi panjang",
}
}
fn main() {
let shapes = [Shape::Circle { radius: 1.0 }, Shape::Rect { w: 2.0, h: 3.0 }];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
}

Output:

lingkaran: 3.14
persegi panjang: 6.00
▶ Coba sendiri

Kalau kamu menyebut sebagian field saja, tambahkan .. di akhir, seperti Shape::Rect { w, .. }. Tanpa itu kamu mendapat E0027, dan nama field yang salah ketik memberi E0026.

Perbaikan 2: Ubah variannya menjadi varian tuple

Section titled “Perbaikan 2: Ubah variannya menjadi varian tuple”

Pilih ini kalau tanda kurung memang yang kamu inginkan: variannya punya satu nilai yang jelas, dan kamu lebih suka menulis Shape::Circle(1.0) di mana-mana. Ubah definisinya, maka pattern Circle(r) menjadi benar:

enum Shape {
Circle(f64), // ✅ sekarang varian tuple: satu nilai tanpa nama
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ tanda kurung cocok untuk varian tuple
Shape::Rect { w, h } => w * h,
}
}
fn main() {
let small = Shape::Circle(1.0); // dibuat dengan tanda kurung juga
let big = Shape::Circle(2.0);
let door = Shape::Rect { w: 1.0, h: 2.0 };
println!("{:.2} {:.2} {:.2}", area(&small), area(&big), area(&door));
}

Output:

3.14 12.56 2.00
▶ Coba sendiri

Ini mengubah tipenya, jadi setiap tempat yang membuat atau mencocokkan Circle juga harus beralih ke tanda kurung. Compiler akan menyebutkan satu per satu. Untuk dua nilai atau lebih, field bernama biasanya lebih jelas.

Perbaikan 3: Cocokkan struct tuple-nya langsung, dan panggil fungsi di guard

Section titled “Perbaikan 3: Cocokkan struct tuple-nya langsung, dan panggil fungsi di guard”

Pilih ini kalau pesannya bilang found associated function dan labelnya bilang `fn` calls are not allowed in patterns (pemanggilan fn tidak boleh ada di pattern). Kamu menulis constructor seperti Celsius::new(d) di tempat yang membutuhkan pattern:

error[E0164]: expected tuple struct or tuple variant, found associated function `Celsius::new`
--> src/main.rs:11:9
|
11 | Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` itu fungsi, bukan pattern
| ^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns

Program di baliknya:

struct Celsius(f64);
impl Celsius {
fn new(degrees: f64) -> Celsius {
Celsius(degrees)
}
}
fn feels(t: Celsius) -> &'static str {
match t {
Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` itu fungsi, bukan pattern
_ => "cool",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
}

Celsius adalah struct tuple, jadi pattern-nya adalah nama struct itu sendiri: Celsius(d). Apa pun yang butuh pemanggilan fungsi atau method masuk ke match guard (if ... setelah pattern):

struct Celsius(f64);
impl Celsius {
fn new(degrees: f64) -> Celsius {
Celsius(degrees)
}
fn is_freezing(&self) -> bool {
self.0 <= 0.0
}
}
fn feels(t: Celsius) -> &'static str {
match t {
Celsius(d) if d > 25.0 => "hangat", // ✅ struct tuple-nya sendiri, ditambah guard
Celsius(_) => "sejuk",
}
}
fn describe(t: &Celsius) -> &'static str {
match t {
t if t.is_freezing() => "membeku", // ✅ method masuk ke guard
_ => "tidak membeku",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
println!("{}", feels(Celsius::new(12.5)));
let Celsius(d) = Celsius::new(-3.0); // ✅ juga bisa dengan `let`
println!("{} derajat", d);
println!("{}", describe(&Celsius::new(-3.0)));
}

Output:

hangat
sejuk
-3 derajat
membeku
▶ Coba sendiri

Kalau field struct-nya private (struct-nya tinggal di modul lain), kamu tidak bisa menulis Celsius(d) di luar modul itu. Kalau begitu, pakai getter di guard, seperti t if t.degrees() > 25.0. Lihat Match guard: menambahkan if.

Perbaikan 4: Hapus tanda kurung setelah konstanta

Section titled “Perbaikan 4: Hapus tanda kurung setelah konstanta”

Pilih ini kalau pesannya bilang found associated constant. Sebuah konstanta sudah merupakan pattern yang lengkap. Ia mencocokkan satu nilai yang persis, jadi tidak ada yang perlu dimasukkan ke dalam tanda kurung:

error[E0164]: expected tuple struct or tuple variant, found associated constant `Volume::MAX`
--> src/main.rs:10:9
|
10 | Volume::MAX(_) => "loudest", // ❌ konstanta tidak memakai ()
| ^^^^^^^^^^^^^^ not a tuple struct or tuple variant

Program di baliknya:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "muted",
Volume::MAX(_) => "loudest", // ❌ konstanta tidak memakai ()
_ => "normal",
}
}
fn main() {
println!("{}", label(10));
}

Tulis konstantanya saja:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "senyap",
Volume::MAX => "paling keras", // ✅ sebuah konstanta, tanpa apa-apa lagi
1..=3 => "pelan",
_ => "normal",
}
}
fn main() {
for level in [0, 2, 7, 10, u8::MAX] {
println!("{}: {}", level, label(level));
}
}

Output:

0: senyap
2: pelan
7: normal
10: paling keras
255: normal
▶ Coba sendiri

Hal yang sama berlaku untuk konstanta dari standard library: u32::MAX(_) adalah E0164, sedangkan u32::MAX adalah pattern yang valid.

Setelah mengubah varian menjadi field bernama. Kamu mengubah Move(i32, i32) menjadi Move { x: i32, y: i32 } supaya lebih jelas. Sekarang setiap cabang lama Command::Move(x, y) => memberi E0164. Perbaikannya: Command::Move { x, y } =>.

Mencocokkan dengan fungsi “parser”. Sesuatu seperti match input { Version::parse(v) => ... }, dengan harapan fungsinya berjalan saat pencocokan. Perbaikannya: panggil fungsinya dulu, lalu cocokkan hasilnya: match Version::parse(input) { Some(v) => ..., None => ... }.

Fungsi biasa, struct biasa, dan varian unit memberi E0532. Kesalahan tanda kurung yang sama dilaporkan sebagai E0532 kalau namanya tidak dicapai lewat sebuah tipe: fungsi biasa (Some(limit()), expected a pattern, found a function call), struct dengan field bernama (let Point(x, y) = p;, found struct `Point` ), atau varian unit (Status::Active()). Perbaikannya sama seperti di halaman ini.

Kuis singkat

1. Untuk enum Shape { Circle { radius: f64 } }, cabang mana yang memakai radiusnya dengan benar?

2. Celsius::new(d) => ... memberi "fn calls are not allowed in patterns". Celsius adalah struct Celsius(f64);. Pattern mana yang berhasil?

3. Bagaimana cara mencocokkan konstanta asosiasi Volume::MAX?

Skor: 0 / 3