Menu
CoddyTech

io.Reader & io.Writer

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 73 dari 107.

standard library Go menunjukkan desain berbasis interface melalui dua interface dasar: io.Reader dan io.Writer. Interface sederhana ini mendukung segala hal, mulai dari operasi file hingga komunikasi jaringan.

Interface io.Reader hanya memerlukan satu method:

type Reader interface {
    Read(p []byte) (n int, err error)
}

Ini membaca hingga len(p) byte ke dalam slice dan mengembalikan jumlah byte yang dibaca. Demikian pula, io.Writer mendefinisikan:

type Writer interface {
    Write(p []byte) (n int, err error)
}

Tipe apa pun yang mengimplementasikan method ini dapat digunakan di seluruh ekosistem I/O.

Berikut tipe kustom yang mengimplementasikan io.Reader:

type RepeatReader struct {
    Char  byte
    Count int
    pos   int
}

func (r *RepeatReader) Read(p []byte) (int, error) {
    if r.pos >= r.Count {
        return 0, io.EOF
    }
    n := 0
    for n < len(p) && r.pos < r.Count {
        p[n] = r.Char
        n++
        r.pos++
    }
    return n, nil
}

Sekarang reader khusus ini berfungsi dengan fungsi apa pun yang mengharapkan io.Reader:

reader := &RepeatReader{Char: 'A', Count: 5}
data, _ := io.ReadAll(reader)
fmt.Println(string(data))  // AAAAA

Desain ini memungkinkan kamu menulis fungsi yang menerima io.Reader atau io.Writer, sehingga fungsi tersebut dapat digunakan dengan file, koneksi jaringan, buffer, atau implementasi kustom apa pun.

challenge icon

Tantangan

Mudah

Mari buat pemroses stream teks khusus yang mengimplementasikan interface io.Reader dan io.Writer! Kamu akan membuat tipe yang dapat mengubah teks saat teks mengalir melaluinya, untuk menunjukkan bagaimana interface dasar ini memungkinkan komposisi I/O yang andal.

Kamu akan menyusun kodemu dalam dua file:

  • streams.go: Definisikan tipe reader dan writer khususmu.

    Buat struct CountingReader yang membungkus sebuah string dan melacak jumlah byte yang telah dibaca. Struct ini harus memiliki field untuk string sumber dan pelacak posisi. Implementasikan method Read(p []byte) (int, error) yang membaca byte dari sumber ke dalam slice yang diberikan, memperbarui posisi, dan mengembalikan io.EOF saat sumber habis.

    Buat struct UppercaseWriter yang mengumpulkan data yang ditulis dan mengubahnya menjadi huruf kapital. Struct ini harus menyimpan hasil yang terkumpul secara internal. Implementasikan method Write(p []byte) (int, error) yang mengubah byte yang masuk menjadi huruf kapital dan menyimpannya. Tambahkan method Result() string untuk mengambil teks huruf kapital yang terkumpul.

    Buat fungsi konstruktor NewCountingReader(source string) *CountingReader dan NewUppercaseWriter() *UppercaseWriter untuk menginisialisasi tipemu dengan benar.

  • main.go: Tunjukkan cara tipe I/O khususmu bekerja dengan standard library.

    Baca input string, lalu gunakan CountingReader milikmu bersama io.ReadAll untuk membaca semua data. Teruskan data tersebut melalui UppercaseWriter milikmu menggunakan method Write.

    Cetak hasil dengan format ini:

    Original: [input]
    Uppercase: [result from writer]
    Bytes read: [total bytes]

Input berikut akan diberikan:

  • Satu baris teks

Contohnya, jika diberikan:

Hello World

Outputmu harus berupa:

Original: Hello World
Uppercase: HELLO WORLD
Bytes read: 11

Dan jika diberikan:

Go interfaces are powerful

Outputmu harus berupa:

Original: Go interfaces are powerful
Uppercase: GO INTERFACES ARE POWERFUL
Bytes read: 26

Inti pentingnya adalah CountingReader milikmu dapat bekerja dengan lancar bersama io.ReadAll karena mengimplementasikan io.Reader. Fungsi apa pun dalam ekosistem Go yang menerima io.Reader akan bekerja dengan tipe khususmu. Itulah keunggulan desain berbasis interface.

Coba sendiri

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main() {
	// Baca input
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	// Hapus karakter baris baru di akhir jika ada
	if len(input) > 0 && input[len(input)-1] == '\n' {
		input = input[:len(input)-1]
	}

	// TODO: Buat CountingReader dengan string input
	// countingReader := NewCountingReader(input)

	// TODO: Gunakan io.ReadAll untuk membaca semua data dari CountingReader-mu
	// data, err := io.ReadAll(countingReader)

	// TODO: Buat UppercaseWriter
	// upperWriter := NewUppercaseWriter()

	// TODO: Tulis data ke UppercaseWriter-mu
	// upperWriter.Write(data)

	// TODO: Cetak hasilnya dalam format yang diminta:
	// Asli: [input]
	// Huruf besar: [hasil dari penulis]
	// Byte yang dibaca: [total byte]

	// Kode sementara untuk menghindari error import yang tidak digunakan. Hapus saat kamu mengimplementasikannya.
	_ = io.EOF
	fmt.Println("Original:", input)
	// fmt.Println("Uppercase:", upperWriter.Result())
	// fmt.Println("Bytes read:", countingReader.Position)
}
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