Mengenal Struct dan Interface Pada Golang
Meskipun mungkin bagi kita untuk menulis program hanya menggunakan tipe data bawaan Go, pada titik tertentu itu akan menjadi sangat membosankan. Pertimbangkan program yang berinteraksi dengan bentuk seperti kode dibawah ini.
1package main
2
3import (
4 "fmt"
5 "math"
6)
7
8func distance(x1, y1, x2, y2 float64) float64 {
9 a := x2 - x1
10 b := y2 - y1
11 return math.Sqrt(a*a + b*b)
12}
13
14func rectangleArea(x1, y1, x2, y2 float64) float64 {
15 l := distance(x1, y1, x1, y2)
16 w := distance(x1, y1, x2, y1)
17 return l * w
18}
19
20func circleArea(x, y, r float64) float64 {
21 return math.Pi * r * r
22}
23
24func main() {
25 var rx1, ry1 float64 = 0, 0
26 var rx2, ry2 float64 = 10, 10
27 var cx, cy, cr float64 = 0, 0, 5
28 fmt.Println(rectangleArea(rx1, ry1, rx2, ry2))
29 fmt.Println(circleArea(cx, cy, cr))
30}Melacak semua koordinat membuat sulit untuk melihat apa yang sedang dilakukan program dan kemungkinan akan menyebabkan kesalahan.
Structs
Cara mudah untuk membuat program ini agar lebih baik adalah dengan menggunakan struct. Sebuah struct adalah tipe yang berisi bidang bernama. Misalnya kita bisa mewakili lingkaran seperti ini:
1type Circle struct {
2 x float64
3 y float64
4 r float64
5}type memperkenalkan tipe baru. Diikuti dengan nama tipe (Lingkaran), kata kunci struct untuk menunjukkan bahwa kita mendefinisikan tipe struct dan daftar bidang di dalam kurung kurawal. Setiap bidang memiliki nama dan jenis. Seperti halnya fungsi, kita dapat menutup bidang yang memiliki tipe yang sama:1type Circle struct {
2 x, y, r float64
3}Inisialiasi
Kita dapat membuat turunan dari tipe Lingkaran baru kita dalam berbagai cara:
1 var c CircleSeperti tipe data lainnya, ini akan membuat variabel Cirlce lokal yang secara default diset ke nol. Untuk struct nol berarti masing-masing bidang diatur ke nilai nol yang sesuai (0 untuk int, 0,0 untuk float, "" untuk string, nil untuk pointer, …) Kita juga dapat menggunakan fungsi new:
1 c := new(Circle)nol dan mengembalikan pointer. (*Circle) Lebih sering kita gunakan untuk memberi nilai pada setiap field. Kita bisa melakukan ini dengan dua cara. Seperti ini:1 c := Circle{x: 0, y: 0, r: 5}1 c := Circle{0, 0, 5}Fields
Kita dapat mengakses field menggunakan . operator:
1 fmt.Println(c.x, c.y, c.r)
2 c.x = 10
3 c.y = 5Mari kita ubah fungsi circleArea sehingga menggunakan Circle:
1func circleArea(c Circle) float64 {
2 return math.Pi * c.r*c.r
3}1 c := Circle{0, 0, 5}
2 fmt.Println(circleArea(c))Satu hal yang perlu diingat adalah bahwa argumen selalu disalin di Go. Jika kita mencoba untuk mengubah salah satu field di dalam fungsi circleArea, itu tidak akan mengubah variabel asli. Karena itu, kita biasanya menulis fungsi seperti ini:
1func circleArea(c *Circle) float64 {
2 return math.Pi * c.r*c.r
3}1 c := Circle{0, 0, 5}
2 fmt.Println(circleArea(&c))Methods
Meskipun ini lebih baik daripada versi pertama dari kode ini, kita dapat mengubahnya dengan menggunakan jenis fungsi khusus yang dikenal sebagai method:
1func (c *Circle) area() float64 {
2 return math.Pi * c.r*c.r
3}receiver. receiver seperti parameter ia memiliki nama dan tipe tetapi dengan membuat fungsi dengan cara ini, kita dapat memanggil fungsi menggunakan . operator:1 fmt.Println(c.area())circle, kita dapat mengganti nama fungsi menjadi area saja.Mari kita lakukan hal yang sama untuk persegi panjang:
1type Rectangle struct {
2 x1, y1, x2, y2 float64
3}
4func (r *Rectangle) area() float64 {
5 l := distance(r.x1, r.y1, r.x1, r.y2)
6 w := distance(r.x1, r.y1, r.x2, r.y1)
7 return l * w
8}main kita memiliki:1r := Rectangle{0, 0, 10, 10}
2fmt.Println(r.area())Embedded Types
Field struct biasanya mewakili saling keterikatan. Misalnya Circle memiliki radius. Misalkan kita memiliki orang struct:
1type Person struct {
2 Name string
3}
4func (p *Person) Talk() {
5 fmt.Println("Hi, my name is", p.Name)
6}struct Android baru. Kita bisa melakukan ini:1type Android struct {
2 Person Person
3 Model string
4}Go mendukung keterikatan struct seperti ini dengan menggunakan tipe yang disematkan. Juga dikenal sebagai bidang anonim, jenis yang disematkan terlihat seperti ini:
1type Android struct {
2 Person
3 Model string
4}Person) dan tidak memberinya nama. Ketika didefinisikan dengan cara ini, struct Person dapat diakses menggunakan nama tipe:1 a := new(Android)
2 a.Person.Talk()Tetapi kita juga dapat memanggil metode Person apa pun secara langsung di Android:
1a := new(Android)
2a.Talk()Interfaces
Baik dalam kehidupan nyata maupun dalam pemrograman, hubungan seperti ini adalah hal yang lumrah. Go memiliki cara untuk membuat kesamaan yang tidak disengaja ini menjadi eksplisit melalui tipe yang dikenal sebagai Interface. Berikut adalah contoh interface Shape:
1type Shape interface {
2 area() float64
3}Seperti sebuah struct, interface dibuat menggunakan type, diikuti dengan nama dan interface. Tapi untuk mendefinisikan Shape, kita membutuhkan "method set".Kumpulan method adalah daftar method yang harus dimiliki suatu tipe untuk “mengimplementasikan” interface.
1func totalArea(shapes ...Shape) float64 {
2 var area float64
3 for _, s := range shapes {
4 area += s.area()
5 }
6 return area
7}1 fmt.Println(totalArea(&c, &r))Interface juga dapat digunakan sebagai fields:
1type MultiShape struct {
2 shapes []Shape
3}MultiShape menjadi Shape dengan memberinya metode area:1func (m *MultiShape) area() float64 {
2 var area float64
3 for _, s := range m.shapes {
4 area += s.area()
5 }
6 return area
7}MultiShape dapat berisi Circles, Rectangles atau bahkan MultiShapes lainnya.Berikut ini program lebih lengkapnya
1package main
2
3import (
4 "fmt"
5 "math"
6)
7
8type Circle struct {
9 x, y, r float64
10}
11
12func (c *Circle) area() float64 {
13 return math.Pi * c.r * c.r
14}
15
16type Rectangle struct {
17 l, w float64
18}
19
20func (r *Rectangle) area() float64 {
21 return r.l * r.w
22}
23
24type Shape interface {
25 area() float64
26}
27
28type MultiShape struct {
29 shapes []Shape
30}
31
32func (m *MultiShape) area() float64 {
33 var area float64
34 for _, s := range m.shapes {
35 area += s.area()
36 }
37 return area
38}
39
40func totalArea(shapes ...Shape) float64 {
41 var area float64
42 for _, s := range shapes {
43 area += s.area()
44 }
45 return area
46}
47
48func main() {
49 c := Circle{0, 0, 5}
50 r := Rectangle{3, 4}
51 fmt.Println(totalArea(&c, &r))
52
53 m := MultiShape{}
54 m.shapes = append(m.shapes, &c, &r)
55 fmt.Println(m.area())
56}