Skip to content

Struct Go

Struct dapat menyimpan sekumpulan data dengan tipe berbeda adalah tipe komposit. Go meninggalkan kelas dan inheritance sekaligus juga meninggalkan konstruktor sengaja melemahkan fungsi berorientasi objek Go bukan bahasa OOP tradisional tetapi Go tetap memiliki bayangan OOP melalui struct dan metode juga dapat mensimulasikan kelas. Berikut adalah contoh struct sederhana

go
type Programmer struct {
  Name     string
  Age      int
  Job      string
  Language []string
}

Deklarasi

Deklarasi struct sangat sederhana contohnya sebagai berikut

go
type Person struct {
   name string
   age int
}

Struct itu sendiri dan field di dalamnya semuanya mematuhi cara penamaan huruf besar dan kecil untuk eksposur. Untuk beberapa field yang berdekatan dengan tipe yang sama tidak perlu mengulang deklarasi tipe sebagai berikut

go
type Rectangle struct {
  height, width, area int
  color               string
}

TIP

Saat mendeklarasikan field struct nama field tidak boleh duplikat dengan nama metode

Instansiasi

Go tidak ada konstruktor sebagian besar situasi menggunakan cara di bawah ini untuk menginstansiasi struct saat inisialisasi seperti map menentukan nama field lalu menginisialisasi nilai field

go
programmer := Programmer{
   Name:     "jack",
   Age:      19,
   Job:      "coder",
   Language: []string{"Go", "C++"},
}

Tetapi juga dapat menghilangkan nama field saat menghilangkan nama field harus menginisialisasi semua field biasanya tidak direkomendasikan menggunakan cara ini karena keterbacaannya sangat buruk.

go
programmer := Programmer{
   "jack",
   19,
   "coder",
   []string{"Go", "C++"}}

Jika proses instansiasi kompleks Anda juga dapat menulis fungsi untuk menginstansiasi struct seperti di bawah ini Anda juga dapat memahaminya sebagai konstruktor

go
type Person struct {
  Name    string
  Age     int
  Address string
  Salary  float64
}

func NewPerson(name string, age int, address string, salary float64) *Person {
  return &Person{Name: name, Age: age, Address: address, Salary: salary}
}

Tetapi Go tidak mendukung overload fungsi dan metode jadi Anda tidak dapat mendefinisikan parameter berbeda untuk fungsi atau metode yang sama. Jika ingin menginstansiasi struct dengan berbagai cara baik membuat beberapa konstruktor atau disarankan menggunakan pola options.

Pola Options

Pola options adalah pola desain yang sangat umum dalam bahasa Go dapat lebih fleksibel menginstansiasi struct kemampuan ekspansi kuat dan tidak perlu mengubah tanda tangan fungsi konstruktor. Misalkan ada struct seperti di bawah ini

go
type Person struct {
  Name     string
  Age      int
  Address  string
  Salary   float64
  Birthday string
}

Deklarasikan tipe PersonOptions menerima parameter tipe *Person harus berupa pointer karena kita akan memberikan nilai pada Person dalam closure.

go
type PersonOptions func(p *Person)

Selanjutnya membuat fungsi options umumnya dimulai dengan With nilai pengembaliannya adalah fungsi closure.

go
func WithName(name string) PersonOptions {
  return func(p *Person) {
    p.Name = name
  }
}

func WithAge(age int) PersonOptions {
  return func(p *Person) {
    p.Age = age
  }
}

func WithAddress(address string) PersonOptions {
  return func(p *Person) {
    p.Address = address
  }
}

func WithSalary(salary float64) PersonOptions {
  return func(p *Person) {
    p.Salary = salary
  }
}

Tanda tangan fungsi konstruktor yang sebenarnya dideklarasikan adalah sebagai berikut menerima parameter tipe PersonOptions variadic.

go
func NewPerson(options ...PersonOptions) *Person {
    // Prioritas menerapkan options
  p := &Person{}
    for _, option := range options {
        option(p)
    }

  // Penanganan nilai default
  if p.Age < 0 {
    p.Age = 0
  }
  ......

    return p
}

Dengan begini untuk kebutuhan instansiasi yang berbeda hanya perlu satu konstruktor即可 menyelesaikan hanya perlu meneruskan fungsi Options yang berbeda

go
func main() {
  pl := NewPerson(
    WithName("John Doe"),
    WithAge(25),
    WithAddress("123 Main St"),
    WithSalary(10000.00),
  )

  p2 := NewPerson(
    WithName("Mike jane"),
    WithAge(30),
  )
}

Pola functional options dapat dilihat di banyak proyek open source cara instansiasi gRPC Server juga menggunakan pola desain ini. Pola functional options hanya cocok untuk instansiasi kompleks jika parameter hanya beberapa sederhana disarankan tetap menggunakan konstruktor biasa untuk menyelesaikannya.

Komposisi

Di Go hubungan antar struct dinyatakan melalui komposisi dapat komposisi eksplisit juga dapat komposisi anonim yang terakhir penggunaannya lebih mirip inheritance tetapi pada dasarnya tidak ada perubahan. Misalnya

Cara komposisi eksplisit

go
type Person struct {
   name string
   age  int
}

type Student struct {
   p      Person
   school string
}

type Employee struct {
   p   Person
   job string
}

Saat menggunakan perlu secara eksplisit menentukan field p

go
student := Student{
   p:      Person{name: "jack", age: 18},
   school: "lili school",
}
fmt.Println(student.p.name)

Sedangkan komposisi anonim tidak perlu secara eksplisit menentukan field

go
type Person struct {
  name string
  age  int
}

type Student struct {
  Person
  school string
}

type Employee struct {
  Person
  job string
}

Nama field anonim secara default adalah nama tipe pemanggil dapat langsung mengakses field dan metode tipe tersebut tetapi selain lebih nyaman tidak ada perbedaan dengan cara pertama.

go
student := Student{
   Person: Person{name: "jack",age: 18},
   school: "lili school",
}
fmt.Println(student.name)

Pointer

Untuk pointer struct tidak perlu dereferensi dapat langsung mengakses konten struct contohnya sebagai berikut

go
p := &Person{
   name: "jack",
   age:  18,
}
fmt.Println(p.age,p.name)

Saat dikompilasi akan dikonversi menjadi (*p).name (*p).age sebenarnya tetap perlu dereferensi tetapi saat pengkodean dapat dihilangkan dianggap sebagai sugar sintaks.

Tag

Tag struct adalah bentuk meta programming dikombinasikan dengan refleksi dapat membuat banyak fungsi ajaib formatnya adalah sebagai berikut

go
`key1:"val1" key2:"val2"`

Tag adalah bentuk key-value dipisahkan dengan spasi. Toleransi kesalahan tag struct sangat rendah jika tidak menulis tag struct sesuai dengan format yang benar maka akan menyebabkan tidak dapat dibaca secara normal tetapi saat dikompilasi tidak akan ada error apa pun di bawah ini adalah contoh penggunaan.

go
type Programmer struct {
    Name     string `json:"name"`
    Age      int `yaml:"age"`
    Job      string `toml:"job"`
    Language []string `properties:"language"`
}

Penggunaan tag struct paling luas adalah definisi alias dalam berbagai format serialisasi penggunaan tag perlu dikombinasikan dengan refleksi untuk sepenuhnya mengeluarkan fungsinya.

Penyelarasan Memori

Distribusi memori field struct Go mengikuti aturan penyelarasan memori ini dilakukan untuk mengurangi jumlah akses CPU ke memori相应nya memori yang ditempati lebih banyak adalah jenis pertukaran ruang untuk waktu. Misalkan ada struct seperti berikut

go
type Num struct {
  A int64
  B int32
  C int16
  D int8
    E int32
}

Diketahui byte yang ditempati oleh tipe-tipe ini

  • int64 menempati 8 byte
  • int32 menempati 4 byte
  • int16 menempati 2 byte
  • int8 menempati satu byte

Apakah penggunaan memori seluruh struct sepertinya 8+4+2+1+4=19 byte tentu saja tidak demikian menurut aturan penyelarasan memori而言 panjang penggunaan memori struct setidaknya adalah kelipatan integer dari field terbesar yang kurang maka dilengkapi. Yang terbesar dalam struct ini adalah int64 menempati 8 byte maka distribusi memori seperti yang ditunjukkan pada gambar di bawah ini

Jadi sebenarnya menempati 24 byte di antaranya 5 byte tidak berguna.

Mari lihat struct di bawah ini

go
type Num struct {
  A int8
  B int64
  C int8
}

Setelah memahami aturan di atas dapat dengan cepat memahami penggunaan memorinya juga 24 byte meskipun hanya memiliki tiga field membuang 14 byte.

Tetapi kita dapat menyesuaikan field mengubah menjadi urutan seperti berikut

type Num struct {
  A int8
  C int8
  B int64
}

Dengan begini memori yang ditempati menjadi 16 byte membuang 6 byte mengurangi pemborosan memori 8 byte.

Secara teoritis membuat field dalam struct didistribusikan sesuai dengan urutan yang wajar dapat mengurangi penggunaan memorinya. Tetapi dalam proses pengkodean aktual tidak ada alasan yang diperlukan untuk melakukan hal ini belum tentu dapat membawa peningkatan substansial dalam mengurangi penggunaan memori tetapi pasti akan meningkatkan tekanan darah dan beban mental pengembang terutama dalam bisnis beberapa field struct mungkin多达 puluhan atau ratusan jadi hanya做 pemahaman即可.

TIP

Jika Anda benar-benar ingin menghemat memori melalui metode ini dapat melihat dua pustaka ini

Mereka akan memeriksa struct dalam kode sumber Anda menghitung dan menata ulang field struct untuk meminimalkan memori yang ditempati struct.

Struct Kosong

Struct kosong tidak memiliki field tidak menempati ruang memori kita dapat melalui fungsi unsafe.SizeOf untuk menghitung ukuran byte yang ditempati

go
func main() {
   type Empty struct {}
   fmt.Println(unsafe.Sizeof(Empty{}))
}

Output

0

Ada banyak skenario penggunaan struct kosong misalnya yang disebutkan sebelumnya sebagai tipe nilai map dapat menggunakan map sebagai set untuk digunakan atau sebagai tipe channel hanya表示 channel tipe notifikasi.

Golang by www.golangdev.cn edit