Error Rust E0368: binary assignment operation += cannot be applied to type
E0368 artinya kamu memakai operator gabungan seperti +=, -=, atau *= pada tipe yang belum mendukungnya. Error ini sepupu += dari E0369. Struct buatanmu tidak otomatis mendapat +=, bahkan kalau sudah mendukung + sekalipun. Perbaikannya biasanya blok impl AddAssign yang pendek, dan untuk angka di balik referensi cukup satu *. Untuk error lain di seri ini, lihat Penjelasan error compiler Rust.
Pesan error-nya
Section titled “Pesan error-nya”error[E0368]: binary assignment operation `+=` cannot be applied to type `Money` --> src/main.rs:8:5 |8 | wallet += tip; // ❌ Money tidak tahu cara melakukan += | ------^^^^^^^ | | | cannot use `+=` on type `Money` |note: an implementation of `AddAssign` might be missing for `Money` --> src/main.rs:1:1 |1 | struct Money { | ^^^^^^^^^^^^ must implement `AddAssign`Compiler bilang += tidak bisa dipakai pada Money, karena Money belum mengimplementasikan AddAssign.
Ini program yang menghasilkan error tersebut:
struct Money { cents: i64,}
fn main() { let mut wallet = Money { cents: 500 }; let tip = Money { cents: 150 }; wallet += tip; // ❌ Money tidak tahu cara melakukan += println!("{}", wallet.cents);}Operator di baris pertama pesannya bisa berubah, tapi error-nya tetap sama. p -= step meminta SubAssign, dan p *= 2 meminta MulAssign<{integer}>, yang artinya “kalikan-lalu-isi dengan sebuah bilangan bulat”.
Apa artinya
Section titled “Apa artinya”Label di bawah sisi kiri menjelaskan apa yang salah: “cannot use += on type Money” (tidak bisa memakai += pada tipe Money). Lalu note: menunjuk struct-mu dan bilang struct itu must implement AddAssign (wajib mengimplementasikan AddAssign). Itulah trait di balik +=.
Bayangkan sebuah celengan. Memasukkan koin ke dalamnya adalah tindakan yang jelas. Tapi kalau seseorang memberimu kotak berlabel “Money” dan bilang “tambahkan kotak lain ini ke situ”, kamu perlu tahu caranya: jumlahkan sennya? tumpuk kotaknya? Rust memintamu menuliskan aturan itu sekali saja.
Kenapa Rust melakukan ini
Section titled “Kenapa Rust melakukan ini”Setiap operator gabungan sebenarnya adalah pemanggilan method yang menyamar. a += b memanggil AddAssign::add_assign(&mut a, b), a -= b memanggil SubAssign::sub_assign, dan seterusnya. Semua trait ini ada di std::ops. Angka sudah mengimplementasikannya. Struct barumu dimulai tanpa satu pun, dan tidak ada #[derive] untuk operator matematika.
Ini bagian yang sering mengejutkan: Add dan AddAssign adalah dua trait terpisah. Meskipun Point sudah mengimplementasikan Add, p += q tetap menghasilkan E0368. Alasannya, keduanya punya tugas berbeda. a + b menerima dua nilai dan mengembalikan nilai baru. a += b mengubah a di tempat lewat &mut self dan tidak mengembalikan apa-apa. Mengubah di tempat bisa jauh lebih hemat: += milik String menambahkan teks ke buffer yang sudah ada, bukan membangun string baru. Rust membiarkan setiap tipe memilih, jadi Rust tidak pernah diam-diam mengubah += menjadi + untukmu.
Trait operator dijelaskan di Trait yang sering dipakai dan Advanced traits.
Cara memperbaikinya
Section titled “Cara memperbaikinya”Perbaikan 1: Implementasikan AddAssign (dan kawan-kawannya)
Section titled “Perbaikan 1: Implementasikan AddAssign (dan kawan-kawannya)”Pilih ini kalau += pada tipemu punya arti yang jelas, seperti menambah uang atau menggeser posisi. Kamu menulis satu method yang mengubah self. Tambahkan SubAssign, MulAssign, dan yang lain dengan cara yang sama saat kamu membutuhkannya:
use std::ops::{AddAssign, SubAssign};
#[derive(Debug)]struct Money { cents: i64,}
impl AddAssign for Money { fn add_assign(&mut self, other: Money) { self.cents += other.cents; }}
impl SubAssign for Money { fn sub_assign(&mut self, other: Money) { self.cents -= other.cents; }}
fn main() { let mut wallet = Money { cents: 500 }; wallet += Money { cents: 150 }; // dapat tip wallet -= Money { cents: 200 }; // beli makan siang println!("{:?}", wallet);}Output:
Money { cents: 450 }Perhatikan &mut self dan tidak adanya tipe kembalian. Hanya itu bedanya dengan Add. Di dalamnya, self.cents += other.cents bisa jalan karena i64 sudah punya AddAssign.
Perbaikan 2: Sudah punya Add? Tulis a = a + b, atau pakai ulang
Section titled “Perbaikan 2: Sudah punya Add? Tulis a = a + b, atau pakai ulang”Pilih ini kalau tipemu sudah mengimplementasikan Add (mungkin setelah memperbaiki E0369). Kalau tipenya Copy, kamu bisa langsung menulis pos = pos + step, yang hanya butuh Add. Atau implementasikan AddAssign dalam satu baris dengan memanggil Add milikmu, supaya += juga bisa dipakai:
use std::ops::{Add, AddAssign};
#[derive(Debug, Clone, Copy)]struct Point { x: i32, y: i32,}
impl Add for Point { type Output = Point;
fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y } }}
impl AddAssign for Point { fn add_assign(&mut self, other: Point) { *self = *self + other; // pakai ulang Add }}
fn main() { let mut pos = Point { x: 0, y: 0 }; let step = Point { x: 1, y: 2 }; pos = pos + step; // hanya butuh Add pos += step; // butuh AddAssign println!("{:?}", pos);}Output:
Point { x: 2, y: 4 }*self = *self + other menyalin nilai saat ini keluar, menjumlahkannya, lalu menulis hasilnya kembali. Ini hanya bisa karena Point adalah Copy. Untuk tipe yang memiliki data di heap (misalnya punya field Vec), tulis versi di tempat seperti di Perbaikan 1.
Perbaikan 3: String: s += &t atau push_str
Section titled “Perbaikan 3: String: s += &t atau push_str”Pilih ini kalau sisi kirinya string. += bekerja pada String yang dimiliki (owned), dan sisi kanannya harus &str. Ada dua kasus yang sering menjebak:
cannot be applied to type `&str`: sisi kirinya string slice seperti"Hello, ".&stradalah tampilan yang hanya bisa dibaca, jadi tidak bisa bertambah panjang. JadikanStringdulu.s += tdengantyang jugaStringbukan E0368. Itu E0308, “expected&str, foundString”, dengan sarans += &t. Cukup pinjam sisi kanannya.
fn main() { let mut greeting = String::from("Halo, "); // owned, jadi bisa bertambah let name = String::from("Ferris");
greeting += &name; // pinjam sisi kanan greeting.push_str("!"); // sama saja, dalam bentuk method
let mut tag = "kepiting".to_string(); // &str di kiri? jadikan String tag += " #1";
println!("{greeting}"); println!("{tag}"); println!("{name} masih bisa dipakai");}Output:
Halo, Ferris!kepiting #1Ferris masih bisa dipakaiKarena sisi kanan hanya dipinjam, name masih milikmu setelahnya. += dan push_str melakukan hal yang persis sama; pakai yang menurutmu lebih enak dibaca. Lihat String.
Perbaikan 4: Tambahkan bound T: AddAssign di kode generik
Section titled “Perbaikan 4: Tambahkan bound T: AddAssign di kode generik”Pilih ini kalau error-nya bilang cannot be applied to type `T`. Di dalam fungsi generik, T bisa tipe apa saja, termasuk yang tidak punya +=. Bagian help dari rustc menyebutkan persis apa yang perlu ditambahkan: consider further restricting type parameter `T` with trait `AddAssign` (coba batasi parameter tipe T dengan trait AddAssign).
use std::ops::AddAssign;
fn total<T>(items: &[T]) -> Twhere T: Copy + Default + AddAssign,{ let mut sum = T::default(); for &item in items { sum += item; } sum}
fn main() { println!("{}", total(&[1, 2, 3])); println!("{}", total(&[0.5, 0.25]));}Output:
60.75Sekarang total bisa dipakai untuk tipe apa pun yang bisa disalin, punya nilai awal, dan mendukung +=: integer, float, dan juga Money milikmu begitu ia mengimplementasikan trait-trait itu. Untuk angka biasa, items.iter().sum() melakukan hal yang sama dalam satu baris. Lihat Generics.
Di mana biasanya kamu melihatnya
Section titled “Di mana biasanya kamu melihatnya”Menghitung dengan HashMap. let count = counts.entry(word).or_insert(0); lalu count += 1; menghasilkan cannot be applied to type `&mut i32`. count adalah referensi, bukan angkanya. Saran rustc: “+= can be used on i32 if you dereference the left-hand side” (+= bisa dipakai pada i32 kalau sisi kirinya di-dereference). Perbaikannya: *count += 1;. Lihat HashMap.
Mengalikan struct dengan sebuah angka. p *= 2 butuh MulAssign<{integer}>, karena sisi kanannya angka, bukan Point lain. Perbaikannya: implementasikan trait-nya untuk tipe sisi kanan tersebut:
impl std::ops::MulAssign<i32> for Point { fn mul_assign(&mut self, factor: i32) { self.x *= factor; self.y *= factor; }}Total berjalan di dalam loop. total += item.price dengan price bertipe Money buatanmu. Perbaikan 1 membuatnya bisa jalan. Kalau kamu lebih suka menulis prices.iter().copied().sum(), itu butuh trait Sum, dan tanpanya kamu mendapat E0277 (“a value of type Money cannot be made by summing an iterator”, nilai Money tidak bisa dibuat dengan menjumlahkan iterator).
Error terkait
Section titled “Error terkait”- E0369: binary operation cannot be applied (operator tidak bisa dipakai). Masalah yang sama untuk
+,==,<, dan operator lain yang tidak mengisi nilai. - E0308: mismatched types (tipe tidak cocok). Ini yang kamu dapat untuk
s += tdengan duaString(pinjam saja:s += &t). - E0277: the trait bound is not satisfied (trait tidak terpenuhi).
+=ada untuk tipe di kiri, tapi tidak dengan tipe di kanan ini, seperticannot add-assign `{float}` to `{integer}`untuktotal += 2.5saattotaladalah integer. - E0384: cannot assign twice (diisi dua kali).
x += 1pada variabel yang dideklarasikan tanpamut. Operatornya tidak masalah, variabelnya saja yang tidak mutable. - Semua error compiler: daftar lengkap halaman error.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Point mengimplementasikan Add, tapi p += q tetap menghasilkan E0368. Kenapa?
2. count berasal dari map.entry(word).or_insert(0). Baris mana yang bisa dikompilasi?
3. s dan t sama-sama String. Bagaimana cara menambahkan t ke s?
Skor: 0 / 3
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- E0368 — Rust error codes index (bahasa Inggris): penjelasan resmi error ini.
std::ops::AddAssign— dokumentasi standard library (bahasa Inggris): trait di balik+=, dengan contoh;SubAssign,MulAssign, dan lainnya ada di daftarstd::ops.- Advanced Traits — The Rust Book (bahasa Inggris): operator overloading dengan
std::opsdan default type parameter sepertiRhs. - Storing UTF-8 Encoded Text with Strings — The Rust Book (bahasa Inggris): kenapa string bertambah panjang dengan
push_strdan+menerima&strdi kanan. - Operator Overloading — Rust by Example (bahasa Inggris): contoh singkat yang bisa dijalankan tentang mengimplementasikan trait operator untuk tipe buatanmu.