Menu
CoddyTech

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.

challenge icon

Tantangan

Mudah

Mari 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 field Value bertipe T.

    Tambahkan method Get pada Wrapper[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) U yang menerapkan fungsi transformasi pada nilai wrapper dan mengembalikan hasilnya. Fungsi ini memerlukan parameter tipe sendiri, yaitu U, 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 menggunakan fmt.Sprintf("%v", ...).

  • main.go: Tunjukkan pola solusi dengan berbagai transformasi.

    Baca penanda tipe (int atau string), lalu baca sebuah nilai. Buat Wrapper dengan tipe yang sesuai.

    Untuk input int: Buat Wrapper[int], lalu gunakan Transform untuk menggandakan nilainya (mengembalikan int), dan gunakan TransformToString untuk mendapatkan representasi string.

    Untuk input string: Buat Wrapper[string], lalu gunakan Transform untuk mendapatkan panjang string (mengembalikan int), dan gunakan TransformToString untuk 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 (int atau string)
  • Baris 2: Nilainya

Contohnya, jika diberikan:

int
25

Outputmu seharusnya:

Original: 25
Transformed: 50
As String: 25

Dan jika diberikan:

string
Hello World

Outputmu seharusnya:

Original: Hello World
Transformed: 11
As String: Hello World

Inti 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
	}
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online