Go Language Specification ( operator Alamat ) tidak memungkinkan untuk mengambil alamat konstan numerik (bukan dari sebuah untyped atau dari diketik konstan).
Operand harus dapat dialamatkan , yaitu, variabel, petunjuk arah pointer, atau operasi pengindeksan slice; atau pemilih bidang dari operan struct beralamat; atau operasi pengindeksan array dari array yang dapat dialamatkan. Sebagai pengecualian untuk persyaratan pengalamatan, x
[dalam ekspresi &x
] mungkin juga merupakan literal komposit (mungkin dalam tanda kurung) .
Untuk alasan mengapa hal ini tidak diperbolehkan, lihat pertanyaan terkait: Temukan alamat konstanta di jalan . Pertanyaan serupa (juga tidak diizinkan untuk mengambil alamatnya): Bagaimana cara menyimpan referensi ke hasil operasi di Go?
Pilihan Anda (coba semua di Go Playground ):
1) Dengan new()
Anda cukup menggunakan new()
fungsi bawaan untuk mengalokasikan nilai nol baru int64
dan mendapatkan alamatnya:
instance := SomeType{
SomeField: new(int64),
}
Tetapi perhatikan bahwa ini hanya dapat digunakan untuk mengalokasikan dan mendapatkan penunjuk ke nilai nol jenis apa pun.
2) Dengan variabel pembantu
Paling sederhana dan direkomendasikan untuk elemen bukan nol adalah dengan menggunakan variabel pembantu yang alamatnya dapat diambil:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3) Dengan fungsi pembantu
Catatan: Fungsi pembantu untuk memperoleh penunjuk ke nilai bukan nol tersedia di github.com/icza/gox
perpustakaan saya , dalam gox
paket, jadi Anda tidak perlu menambahkan ini ke semua proyek Anda di mana Anda membutuhkannya.
Atau jika Anda membutuhkan ini berkali-kali, Anda dapat membuat fungsi helper yang mengalokasikan dan mengembalikan *int64
:
func create(x int64) *int64 {
return &x
}
Dan menggunakannya:
instance3 := SomeType{
SomeField: create(3),
}
Perhatikan bahwa kami sebenarnya tidak mengalokasikan apa pun, kompilator Go melakukannya ketika kami mengembalikan alamat argumen fungsi. Kompilator Go melakukan analisis escape, dan mengalokasikan variabel lokal pada heap (bukan stack) jika variabel tersebut dapat lolos dari fungsi. Untuk detailnya, lihat Apakah mengembalikan sepotong larik lokal dalam fungsi Go aman?
4) Dengan fungsi anonim satu baris
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Atau sebagai alternatif (lebih pendek):
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5) Dengan slice literal, indexing dan taking address
Jika Anda ingin *SomeField
menjadi selain 0
, maka Anda membutuhkan sesuatu yang dapat dialamatkan.
Anda masih bisa melakukannya, tapi itu jelek:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField)
Apa yang terjadi di sini adalah []int64
irisan dibuat dengan literal, memiliki satu elemen ( 5
). Dan itu diindeks (elemen ke-0) dan alamat elemen ke-0 diambil. Di latar belakang, sebuah array [1]int64
juga akan dialokasikan dan digunakan sebagai backing array untuk slice. Jadi ada banyak boilerplate di sini.
6) Dengan bantuan struct literal
Mari kita periksa pengecualian untuk persyaratan kemampuan alamat:
Sebagai pengecualian untuk persyaratan pengalamatan, x
[dalam ekspresi &x
] mungkin juga merupakan literal komposit (mungkin dalam tanda kurung) .
Ini berarti bahwa mengambil alamat literal komposit, misalnya struct literal tidak masalah. Jika kita melakukannya, kita akan memiliki nilai struct yang dialokasikan dan pointer yang diperoleh. Namun jika demikian, persyaratan lain akan tersedia untuk kita: "pemilih bidang dari operand struct beralamat" . Jadi jika struct literal berisi sebuah field dari tipe int64
, kita juga dapat mengambil alamat dari field tersebut!
Mari kita lihat opsi ini beraksi. Kami akan menggunakan tipe struct pembungkus ini:
type intwrapper struct {
x int64
}
Dan sekarang kita bisa melakukan:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Perhatikan bahwa ini
&(&intwrapper{6}).x
berarti sebagai berikut:
& ( (&intwrapper{6}).x )
Tapi kita bisa menghilangkan tanda kurung "luar" karena operator alamat &
diterapkan ke hasil ekspresi selektor .
Perhatikan juga bahwa di latar belakang hal berikut akan terjadi (ini juga merupakan sintaks yang valid):
&(*(&intwrapper{6})).x
7) Dengan pembantu anonymous struct literal
Prinsipnya sama dengan kasus # 6, tetapi kita juga dapat menggunakan literal struct anonim, jadi tidak perlu definisi tipe struct helper / wrapper:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}