26. Struct dan metode — Solusi PR
File solusi .go ada di
exercises/26/homework/solutions/.
Soal 1 — Penghitung
Soal. Struct counter dengan metode
inc, get, dan reset.
Cara berpikir. Struct menyimpan keadaannya di
count. Receiver nilai mendapat salinan, jadi
inc dan reset mengubah salinannya lalu
mengembalikannya. get hanya membaca, jadi metode ini
mengembalikan int.
Solusi yang dikerjakan.
package main
import "fmt"
type counter struct {
count int
}
func (c counter) inc() counter {
c.count = c.count + 1
return c
}
func (c counter) get() int {
return c.count
}
func (c counter) reset() counter {
c.count = 0
return c
}
func main() {
c := counter{}
fmt.Println(c.get()) // 0
c = c.inc()
fmt.Println(c.get()) // 1
c = c.inc()
c = c.inc()
fmt.Println(c.get()) // 3
c = c.reset()
fmt.Println(c.get()) // 0
}Kesalahan umum.
- Menulis
c.inc()di satu baris tersendiri. Kode ini bisa dikompilasi, danctidak berubah. Tugaskan hasilnya:c = c.inc(). - Tidak menulis receiver. Go lalu berhenti dengan
c.inc undefined (type counter has no field or method inc). - Menulis
c.gettanpa tanda kurung di dalamfmt.Println. Kode ini bisa dikompilasi, dango vetmemberi peringatan, tetapi yang tercetak adalah sebuah alamat, bukan hitungannya.
Soal 2 — Anjing yang menggonggong
Soal. Dua nilai dog dengan namanya
sendiri, masing-masing memanggil bark()-nya.
Cara berpikir. Setiap literal membuat nilai terpisah
dengan name-nya sendiri. Kode metode yang sama berjalan
untuk keduanya, dan receiver-nya anjing yang berbeda setiap kali.
bark tidak mengubah apa pun, jadi metode ini tidak
mengembalikan apa-apa.
Solusi yang dikerjakan.
package main
import "fmt"
type dog struct {
name string
}
func (d dog) bark() {
fmt.Printf("%s: Woof!\n", d.name)
}
func main() {
rex := dog{name: "Rex"}
lassie := dog{name: "Lassie"}
rex.bark() // Rex: Woof!
lassie.bark() // Lassie: Woof!
}Kesalahan umum.
- Memakai variabel
namedi luar fungsi, bukand.name. Kedua anjing lalu mencetak nama yang sama.
Soal 3 — Kalkulator
Soal. Struct calc dengan metode
aritmetika yang memperbarui sebuah nilai.
Cara berpikir. Ketiga metode aritmetika punya bentuk
yang sama: ubah salinannya, lalu kembalikan. Nama total
membuat variabelnya tidak tampak seperti tipenya.
Solusi yang dikerjakan.
package main
import "fmt"
type calc struct {
value int
}
func (c calc) add(n int) calc {
c.value = c.value + n
return c
}
func (c calc) sub(n int) calc {
c.value = c.value - n
return c
}
func (c calc) mul(n int) calc {
c.value = c.value * n
return c
}
func (c calc) show() {
fmt.Printf("Value: %d\n", c.value)
}
func main() {
total := calc{}
total = total.add(10)
total.show() // Value: 10
total = total.mul(3)
total.show() // Value: 30
total = total.sub(5)
total.show() // Value: 25
}Setiap metode mengembalikan calc, jadi pemanggilannya
juga bisa berurutan dalam satu baris:
total = total.add(10).mul(3) memberikan
30.
Kesalahan umum.
- Lupa menulis
return cpada metode yang menjanjikancalc. Go berhenti denganmissing return. - Menamai variabelnya
calcjuga. Variabel itu lalu menutupi tipenya sampai akhir fungsi, jadicalc{}berikutnya berhenti dengancalc (variable of type calc) is not a type.
Tantangan — Stack
Soal. Stack berisi string dengan push,
pop, peek, dan size.
Cara berpikir. Puncaknya adalah ujung slice.
append menambah di sana, dan s.items[:last]
membuangnya. pop punya dua hal untuk dikembalikan, stack
yang lebih pendek dan item-nya, jadi metode ini mengembalikan dua nilai,
seperti yang ditunjukkan Bab 21.
Solusi yang dikerjakan.
package main
import "fmt"
type stack struct {
items []string
}
func (s stack) push(v string) stack {
s.items = append(s.items, v)
return s
}
func (s stack) pop() (stack, string) {
last := len(s.items) - 1
top := s.items[last]
s.items = s.items[:last]
return s, top
}
func (s stack) peek() (string, bool) {
if len(s.items) == 0 {
return "", false
}
return s.items[len(s.items)-1], true
}
func (s stack) size() int {
return len(s.items)
}
func main() {
s := stack{}
s = s.push("a")
s = s.push("b")
s = s.push("c")
fmt.Println(s.size()) // 3
top, ok := s.peek()
fmt.Println(top, ok) // c true
s, top = s.pop()
fmt.Println(top) // c
s, top = s.pop()
fmt.Println(top) // b
fmt.Println(s.size()) // 1
}Output:
3
c true
c
b
1
Kesalahan umum.
- Tidak menjaga
peek. Pada stack kosong,s.items[len(s.items)-1]crash denganpanic: runtime error: index out of range [-1]. - Memanggil
popini pada stack kosong, yang crash dengan cara yang sama. Bab 30 merancang stack yang menolak dengan aman. - Mengambil item dari depan dengan
s.items[0]. Itu membuat antrean, yaitu item pertama yang masuk menjadi yang pertama keluar.
Selesai?
Kamu bisa mengelompokkan data dalam struct dan memberinya metode. Tetapi menugaskan kembali setelah setiap perubahan itu merepotkan. Bab berikutnya, Pointer, memungkinkan metode mengubah aslinya.