Cara Alternatif untuk Method Generik
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 71 dari 107.
Go memiliki batasan yang perlu diperhatikan: kamu tidak dapat mendefinisikan method dengan parameter tipe sendiri pada struct. Meskipun struct generik berfungsi dengan baik, kamu tidak boleh menambahkan method yang memperkenalkan parameter tipe baru.
Kode ini tidak akan dikompilasi:
type Box[T any] struct {
Value T
}
// ERROR: method tidak boleh memiliki parameter tipe
func (b Box[T]) Convert[U any](fn func(T) U) U {
return fn(b.Value)
}Solusinya adalah menggunakan fungsi generik mandiri, bukan method:
type Box[T any] struct {
Value T
}
// method biasa, menggunakan parameter tipe milik struct
func (b Box[T]) Get() T {
return b.Value
}
// Fungsi mandiri, dapat memiliki parameter tipe sendiri
func Convert[T, U any](b Box[T], fn func(T) U) U {
return fn(b.Value)
}
func main() {
intBox := Box[int]{Value: 42}
// Gunakan method
fmt.Println(intBox.Get()) // 42
// Gunakan fungsi mandiri
strResult := Convert(intBox, func(n int) string {
return fmt.Sprintf("Number: %d", n)
})
fmt.Println(strResult) // Angka: 42
}Method pada struct generik tetap dapat menggunakan parameter tipe struct T. Pembatasan ini hanya berlaku untuk penambahan parameter tipe tambahan pada signature method.
Saat kamu membutuhkan fleksibilitas itu, fungsi generik yang menerima struct sebagai argumen pertamanya memberikan hasil yang sama.
Tantangan
MudahMari buat toolkit transformasi data yang menunjukkan solusi untuk keterbatasan Go terkait method generik! Karena method tidak dapat memperkenalkan parameter tipe baru, kamu akan membuat fungsi generik mandiri yang memberikan fleksibilitas serupa.
Kamu akan mengatur kodemu dalam dua file:
wrapper.go: Definisikan container generik dan fungsi transformasimu.Buat struct generik
Wrapper[T any]dengan satu fieldValuebertipeT.Tambahkan method
GetpadaWrapper[T]yang mengembalikan nilai yang dibungkus. Method ini menggunakan parameter tipe struct, yang diperbolehkan.Buat fungsi generik mandiri
Transform[T, U any](w Wrapper[T], fn func(T) U) Uyang menerapkan fungsi transformasi pada nilai wrapper dan mengembalikan hasilnya. Fungsi ini memerlukan parameter tipe sendiri, yaituU, untuk tipe output, sehingga harus berupa fungsi mandiri dan bukan method.Buat fungsi mandiri lainnya,
TransformToString[T any](w Wrapper[T]) string, yang mengonversi nilai yang dibungkus menjadi string menggunakanfmt.Sprintf("%v", ...).main.go: Tunjukkan pola solusi dengan berbagai transformasi.Baca penanda tipe (
intataustring), lalu baca sebuah nilai. BuatWrapperdengan tipe yang sesuai.Untuk input
int: BuatWrapper[int], lalu gunakanTransformuntuk menggandakan nilainya (mengembalikan int), dan gunakanTransformToStringuntuk mendapatkan representasi string.Untuk input
string: BuatWrapper[string], lalu gunakanTransformuntuk mendapatkan panjang string (mengembalikan int), dan gunakanTransformToStringuntuk mendapatkan representasi string.Cetak hasilnya dalam format ini:
Original: [value] Transformed: [transformed value] As String: [string representation]
Input berikut akan diberikan:
- Baris 1: Penanda tipe (
intataustring) - Baris 2: Nilainya
Contohnya, jika diberikan:
int
25Outputmu seharusnya:
Original: 25
Transformed: 50
As String: 25Dan jika diberikan:
string
Hello WorldOutputmu seharusnya:
Original: Hello World
Transformed: 11
As String: Hello WorldInti utamanya adalah Transform menerima Wrapper[T] sebagai argumen pertamanya dan memperkenalkan parameter tipe baru, U, untuk tipe nilai kembalian. Hal ini tidak dapat dilakukan jika berupa method pada struct. Pola ini memberimu fleksibilitas transformasi generik sambil tetap mematuhi batasan sistem tipe Go.
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Baca penanda tipe
typeIndicator, _ := reader.ReadString('\n')
typeIndicator = strings.TrimSpace(typeIndicator)
// Baca nilai
value, _ := reader.ReadString('\n')
value = strings.TrimSpace(value)
if typeIndicator == "int" {
// Ubah nilai menjadi integer
num, _ := strconv.Atoi(value)
// TODO: Buat Wrapper[int] dengan angka yang sudah diubah
// TODO: Gunakan Transform untuk menggandakan nilai (petunjuk: berikan fungsi yang menggandakan nilai)
// TODO: Gunakan TransformToString untuk mendapatkan representasi string
// TODO: Cetak hasil dalam format yang diminta:
// Original: [value]
// Transformed: [transformed value]
// As String: [string representation]
_ = num // Hapus baris ini saat kamu menggunakan num
} else if typeIndicator == "string" {
// TODO: Buat Wrapper[string] dengan nilai tersebut
// TODO: Gunakan Transform untuk mendapatkan panjang string (petunjuk: berikan fungsi yang mengembalikan len())
// TODO: Gunakan TransformToString untuk mendapatkan representasi string
// TODO: Cetak hasil dalam format yang diminta:
// Original: [value]
// Transformed: [transformed value]
// As String: [string representation]
_ = value // Hapus baris ini saat kamu menggunakan value
}
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online