Saya memiliki tipe struct dengan *int64
bidang.
type SomeType struct {
SomeField *int64
}
Di beberapa titik dalam kode saya, saya ingin menyatakan literal ini (katakanlah, ketika saya tahu nilai tersebut harus 0, atau menunjuk ke 0, Anda tahu apa yang saya maksud)
instance := SomeType{
SomeField: &0,
}
... kecuali ini tidak berhasil
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value
Jadi saya coba ini
instance := SomeType{
SomeField: &int64(0),
}
... tapi ini juga tidak berhasil
./main.go:xx: cannot take the address of int64(0)
Bagaimana saya melakukan ini? Satu-satunya solusi yang bisa saya dapatkan adalah menggunakan variabel placeholder
var placeholder int64
placeholder = 0
instance := SomeType{
SomeField: &placeholder,
}
Catatan: Sunting: tidak. Maaf soal ini.&0
sintaksnya berfungsi dengan baik jika berupa * int, bukan *int64
.
Edit:
Rupanya, pertanyaan saya terlalu ambigu. Saya sedang mencari cara untuk menyatakan a *int64
. Ini bisa digunakan di dalam konstruktor, atau untuk menyatakan nilai struct literal, atau bahkan sebagai argumen untuk fungsi lain. Tapi fungsi pembantu atau menggunakan tipe yang berbeda bukanlah solusi yang saya cari.
var _ *int64 = pointer.Int64(64)
Jawaban:
Go Language Specification ( operator Alamat ) tidak memungkinkan untuk mengambil alamat konstan numerik (bukan dari sebuah untyped atau dari diketik konstan).
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 baruint64
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 , dalamgox
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 selain0
, maka Anda membutuhkan sesuatu yang dapat dialamatkan.Anda masih bisa melakukannya, tapi itu jelek:
instance5 := SomeType{ SomeField: &[]int64{5}[0], } fmt.Println(*instance2.SomeField) // Prints 5
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:
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, }
sumber
instance
objek yang berbeda akan menunjuk ke dua yang berbedaint64
. Tapi tampaknya itu memenuhi maksud OP secara memadai&[]int64{2}[0]
saya merasa berdasarkan deskripsi konstanta di blog.golang.org/constants ini seharusnya berfungsi sebagai&0
.instance
objek yang berbeda akan menunjuk ke yang samaint64
dan satu akan memodifikasi objek yang ditunjuk, keduanya akan berubah. Dan bagaimana jika sekarang Anda menggunakan literal yang sama untuk membuat yang ketigainstance
? Alamat yang sama sekarang akan menunjuk keint64
nilai yang berbeda ... jadi alamat yang berbeda harus digunakan, tapi mengapa menggunakan yang sama dalam kasus 2 yang pertama?Gunakan fungsi yang mengembalikan alamat variabel int64 untuk menyelesaikan masalah.
type myStr struct { url *int64 } func main() { f := func(s int64) *int64 { return &s } myStr{ url: f(12345), } }
sumber