Hoy aprendí: Pase por referencia pada Parámetro Interface di Golang

Dimasa-masa kuliah, saya pernah belajar tentang 2 cara untuk membuat parameter pada sebuah fungsi, yaitu: Pass by Value ( PBV ) dan Pass by Reference ( PBR ). Kedua metode ini masing-masing memiliki kelebihan dan kekurangan serta penggunannya juga berbeda. Tidak sedikit orang yang sering terjebak dan bingung dengan kedua konsep metode ini.

Sederhananya, PBV ditandai dengan membuat parámetro yang bukan berupa puntero (menunjuk) pada suatu alamat memori. Sedangkan PBR ditandai dengan membuat parámetro yang menunjuk pada suatu alamat memori.

Dalam Golang, kedua metode ini dapat dilihat dalam bentuk berikut.

  func passByValue ( cadena de elemento) {} 
func passByReference (item * string ) {}

Pase por referencia y pase por valor en Golang

Bicara tentang contoh dan penjelasan lengkap tentang Pase por referencia dan Pase por valor kita dapat menemukannya di internet. Khususnya tentang Golang.

Namun meskipun demikian, berikut saya sertakan contoh sederhana penggunaan PBR dan PBV

  paquete principal 
  importar ( 
"fmt"
)
  func main () { 
elemento: = ""
passByValue (elemento)
fmt.Println (artículo)
passByReference (& item)
fmt.Println (artículo)
}
  func passByValue (cadena de elemento) { 
item = "hola"
}
  func passByReference (item * string) { 
* item = "mundo"
}

Di atas merupakan contoh penggunaan fungsi PBR dan PBV yang sering saya gunakan.

Pase por referencia en el parámetro de interfaz en Golang

No , beberapa hari yang lalu, saya menemukan satu tema sederhana, tetapi cukup memusingkan. Emitir ini tentang PBR pada Golang yang menggunakan interfaz pada parameternya. Tidak seperti biasanya, interface{} fungsi ini menerima interface{} dan akan mengisi nilai param terebut lógica berdasarkan di dalamnya.

Berikut adalah contohnya.

  func doSomethingWithThisParam (interfaz del elemento {}) {} 

Hongos ini cukup sederhana, interfaz de parámetros hanya menerima sebuah dan di dalamnya parámetro tersebut akan di hydrate dan di isi value .

Untuk mencoba memahami dan menyelesaikan masalah ini, saya juego de palabras melakukan beberapa percobaan yang akan saya jelaskan dibawah.

Percobaan 1: Puntero a la interfaz [No funcionó]

Pada percobaan pertama, saya mencoba seperti layaknya puntero de parámetro lainnya. Saya langsung menambahkan puntero pada parámetro fungsi tersebut. Namun langkah ini sepertinya tidak membuahkan hasil.

  paquete principal 
  importar ( 
"fmt"
)
  func main () { 
elemento var Estudiante
doSomethinWithThisParam (& item)
fmt.Printf ("% + v", elemento)
}
  escriba Estructura del estudiante { 
Cadena de identificación
Cadena de nombre
}
  func doSomethinWithThisParam (item * interface {}) { 
* item = & Estudiante {
ID: "124",
Nombre: "Iman Tumorang",
}
}

Jika dijalankan, código tersebut akan error de compilación de lanzamiento . Código Artinya tersebut tidak layak untuk dijalankan.

  no se puede usar & item (type * Student) como type * interface {} en el argumento de doSomethinWithThisParam: 
* interfaz {} es puntero a interfaz, no interfaz

Percobaan 2: Asignar valor directamente a la interfaz [No funcionó]

Pada percobaan kedua, saya pun mencoba tanpa puntero pada interfaz de parámetros fungsi tersebut. Namun didalamnya, saya langsung memberikan nilai pada parámetro tersebut.

  func doSomethinWithThisParam (interfaz del elemento {}) { 
item = & Estudiante {
ID: "124",
Nombre: "Iman Tumorang",
}
}
  // Imprimir: {ID: Nombre:} 

Dan sama seperti percobaan sebelumnya, percobaan ini juga gagal. Nilainya tidak berisi.

Percobaan 3: Transmitir al tipo original y asignar el valor [Funcionó pero …]

Selanjutnya, saya juego de palabras mencari alternatif lain. Sama seperti percobaan 2, saya tetap melakukan tanpa puntero pada parámetro fungsi saya. Namun bedanya, kali ini saya lakukan interfaz de casting tersebut kembali ke wujud originalnya.

Tetapi untuk melakukan ini, saya harus benar-benar hati-hati dan teliti. Karena ada comportamiento yang aneh dan unik ketika melakukannya. Jelasnya perhatikan contoh berikut dibawah.

No funcionó uno
Berikut contoh yang tidak bisa berjalan dengan baik. Nilainya tetap kosong.

  func doSomethinWithThisParam (interfaz del elemento {}) { 
origen: = ítem. (* Estudiante)
origen = & Estudiante {
ID: "124",
Nombre: "Iman Tumorang",
}
}
  // Imprimir: {ID: Nombre:} 

Trabajado uno
Lalu ini yang bisa berjalan dengan baik. Nilainya diisi oleh valor yang saya isi.

  func doSomethinWithThisParam (interfaz del elemento {}) { 
origen: = ítem. (* Estudiante)
origin.Name = "Iman Tumorang"
origin.ID = "124"
}
  // Imprimir: {ID: 124 Nombre: Iman Tumorang} 

Sedikit aneh, awalnya saya penasaran apa bedanya antara asignar el valor del puntero de langsung, dari pada asignar el dengan langsung ke campo seperti diatas.

¿Bagaimana mungkin jika saya lakukan seperti berikut dibawah tidak berjalan dengan baik?

  origen: = ítem. (* Estudiante) 
origen = & Estudiante {
ID: "124",
Nombre: "Iman Tumorang",
}

Namun ketika saya lakukan seperti berikut dibawah malah berjalan dengan baik?

  origen: = ítem. (* Estudiante) 
origin.Name = "Iman Tumorang"

Butuh beberapa menit untuk memahami ini, meski pada akhirnya saya paham juga. Tetapi ini cukup bikin penasaran dan kzl !

Otro funcionó
Setelah mencoba beberapa hal, akhirnya saya mengerti juga. Yang pertama tidak bisa karena saya membuat alamat baru pada interfaz yang saya casting. Valor de Bukan malah mengisi, dirección de tetapi saya malah mengganti. Parámetro dan karena tersebut sudah memiliki dirección sebelumnya, jika kita ubah maka tidak akan memberikan efecto kepada función llamador .

Lalu, untuk membuktikan hipotesa saya, berikut saya buat, dan berhasil.

  func doSomethinWithThisParam (interfaz del elemento {}) { 
origen: = ítem. (* Estudiante)
* origen = Estudiante {
ID: "124",
Nombre: "Iman Tumorang",
}
}
  // Imprimir: {ID: 124 Nombre: Iman Tumorang} 

Resolver final
Setelah cukup lama bereksperimen, akhirnya saya menetapkan pilihan solusi saya. Dan karena fungsi ini menerima interface, artinya bakal jadi generic. Maka saya juego de palabras menambahkan switch-case sesuai kebutuhan.

Jika dilihat, simplenya, berikut contoh código completo saya.

Conclusiones

Emitir ini cukup serius, dan bikin pusing. Kita harus benar-benar hati-hati ketika bekerja yang berhubungan dengan Pase por referencia dan interface {} di Golang. Untuk menghindari bug-bug lucu, saya sangat menyarankan teman-teman untuk menambahkan prueba de unidad pada setiap fungsi yang comportamiento memiliki Pasar por referencia.

Jujur saja, saya terjebak hampir satu jam lebih untuk issue ini. Jika menurut teman-teman hal ini adalah hal yang baik untuk diketahui, compartir artículo ini ke siapapun yang mungkin membutuhkannya, sehingga tidak perlu terjebak ke lubang yang sama jeje: D.