Go'da birebir * int64 nasıl yaparım?


113

Alanlı bir yapı tipim var *int64.

type SomeType struct {
    SomeField *int64
}

Kodumun bir noktasında, bunu birebir beyan etmek istiyorum (örneğin, söz konusu değerin 0 olması gerektiğini bildiğimde veya 0'ı gösterdiğimde, ne demek istediğimi anlıyorsunuz)

instance := SomeType{
    SomeField: &0,
}

... dışında bu işe yaramaz

./main.go:xx: cannot use &0 (type *int) as type *int64 in field value

Bu yüzden bunu deniyorum

instance := SomeType{
    SomeField: &int64(0),
}

... ama bu da çalışmıyor

./main.go:xx: cannot take the address of int64(0)

Bunu nasıl yaparım? Bulabildiğim tek çözüm, bir yer tutucu değişken kullanmak

var placeholder int64
placeholder = 0

instance := SomeType{
    SomeField: &placeholder,
}

Not: &0sözdizimi çalışır cezası yanında bir * int bir yerine geldiğinde *int64. Düzenleme: hayır değil. Bunun için üzgünüm.

Düzenle:

Görünüşe göre sorumda çok fazla belirsizlik vardı. Kelimenin tam anlamıyla a'yı belirtmenin bir yolunu arıyorum *int64. Bu, bir kurucu içinde veya değişmez yapı değerlerini belirtmek için veya hatta diğer işlevlere argümanlar olarak kullanılabilir. Ancak yardımcı işlevler veya farklı bir tür kullanmak aradığım çözümler değil.


1
İnt bir işaretçi ile aynı miktarda yer kapladığından int için işaretçiler talihsizdir, bu nedenle yer tasarrufu sağlamazsınız. Yalnızca değerinden daha karmaşık olan bir NULL değeri ekler. Çoğu durumda 0 yeterli olur. Ekstra bir değere ihtiyacınız varsa, bir "IsValidSomeField" bool'u da çalışır ve bu bool'a daha iyi bir ad verirseniz, bu ekstra değere neden ihtiyaç duyduğunuz hakkında daha fazla bilgi verebilir, bu okunabilirlik açısından iyidir.
voutasaurus

3
Paket işaretçisini kullanabilirsiniz , örneğin:var _ *int64 = pointer.Int64(64)
Xor

Bu o kadar üzücü ki, bunu yapabilmek için bir işlev veya hatta bir kitaplık yazmamız gerekiyor.
Hindistan cevizi

Yanıtlar:


226

Go Dil Spesifikasyonu ( Adres operatörleri ) bir sayısal sabitin ( türlenmemiş veya yazılan sabitin değil) adresini almaya izin vermez .

İşlenen adreslenebilir , yani bir değişken, işaretçi indirimi veya dilim indeksleme işlemi olmalıdır; veya adreslenebilir yapı işleneni alan seçicisi; veya adreslenebilir bir dizinin dizi indeksleme işlemi. Adreslenebilirlik gereksinimine bir istisna olarak, x[ifadesindeki &x] bir (muhtemelen parantez içinde) birleşik sabit bilgi de olabilir .

Neden buna izin verilmediğini anlamak için ilgili soruya bakın: Hareket halindeyken sabitin adresini bulun . Benzer bir soru (benzer şekilde adresini almasına izin verilmez): Go'da bir işlemin sonucuna ilişkin referansı nasıl saklayabilirim?

Seçenekleriniz (hepsini Go Oyun Alanında deneyin ):

1) İle new()

new()Yeni bir sıfır değerli tahsis etmek int64ve adresini almak için yerleşik işlevini kullanabilirsiniz :

instance := SomeType{
    SomeField: new(int64),
}

Ancak bunun yalnızca herhangi bir türün sıfır değerine bir gösterici tahsis etmek ve elde etmek için kullanılabileceğini unutmayın.

2) Yardımcı değişken ile

Sıfır olmayan öğeler için en basit ve önerilen, adresi alınabilen bir yardımcı değişken kullanmaktır:

helper := int64(2)
instance2 := SomeType{
    SomeField: &helper,
}

3) Yardımcı işlevi ile

Not: Sıfırdan farklı bir değere işaretçi edinmeye yönelik yardımcı işlevler, github.com/icza/goxkitaplığımda, goxpakette mevcuttur, bu nedenle bunları ihtiyacınız olan tüm projelerinize eklemeniz gerekmez.

Veya buna birçok kez ihtiyacınız varsa, aşağıdakileri ayıran ve döndüren bir yardımcı işlev oluşturabilirsiniz *int64:

func create(x int64) *int64 {
    return &x
}

Ve bunu kullanarak:

instance3 := SomeType{
    SomeField: create(3),
}

Aslında hiçbir şey ayırmadığımıza dikkat edin, Go derleyicisi bunu işlev bağımsız değişkeninin adresini döndürdüğümüzde yaptı. Go derleyicisi, kaçış analizi gerçekleştirir ve işlevden çıkabilirlerse, yığın üzerinde yerel değişkenleri (yığın yerine) tahsis eder. Ayrıntılar için bkz. Go işlevinde yerel dizinin bir dilimini döndürmek güvenli midir?

4) Tek satırlık anonim işlev ile

instance4 := SomeType{
    SomeField: func() *int64 { i := int64(4); return &i }(),
}

Veya (daha kısa) bir alternatif olarak:

instance4 := SomeType{
    SomeField: func(i int64) *int64 { return &i }(4),
}

5) Dilim değişmezi, indeksleme ve adres alma ile

İstediğiniz istiyorsanız *SomeFielddışında olması 0, o zaman bir şey adreslenebilir gerekir.

Hala yapabilirsin, ama bu çirkin:

instance5 := SomeType{
    SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5

Burada olan şey []int64, bir öğeye ( 5) sahip olan bir dilimin değişmez değerle yaratılmasıdır . Ve indekslenir (0. element) ve 0. elementin adresi alınır. Arka planda bir dizi [1]int64de tahsis edilecek ve dilim için destek dizisi olarak kullanılacaktır. Yani burada pek çok standart metin var.

6) Bir yardımcı yapı hazır bilgisi ile

Adreslenebilirlik gereksinimlerindeki istisnayı inceleyelim:

Adreslenebilirlik gereksinimine bir istisna olarak, x[ifadesindeki &x] bir (muhtemelen parantez içinde) birleşik sabit bilgi de olabilir .

Bu, birleşik bir değişmezin adresini almanın, örneğin bir struct literal'in uygun olduğu anlamına gelir. Bunu yaparsak, tahsis edilen struct değerine ve ona elde edilen bir göstericiye sahip oluruz. Fakat eğer öyleyse, başka bir gereksinim bizim için geçerli olacaktır: "adreslenebilir yapı işleneni alan seçicisi" . Yani yapı değişmezi bir tür alanı içeriyorsa int64, o alanın adresini de alabiliriz!

Bu seçeneği iş başında görelim. Bu sarmalayıcı yapı türünü kullanacağız:

type intwrapper struct {
    x int64
}

Ve şimdi yapabiliriz:

instance6 := SomeType{
    SomeField: &(&intwrapper{6}).x,
}

Bunu unutmayın

&(&intwrapper{6}).x

şu anlama gelir:

& ( (&intwrapper{6}).x )

Ancak, adres operatörü seçici ifadenin& sonucuna uygulandığı için "dış" parantezi atlayabiliriz .

Ayrıca arka planda aşağıdakilerin olacağını unutmayın (bu aynı zamanda geçerli bir sözdizimidir):

&(*(&intwrapper{6})).x

7) Yardımcı anonim yapı hazır bilgisi ile

İlke 6 numaralı durumla aynıdır, ancak anonim bir yapı değişmezi de kullanabiliriz, bu nedenle yardımcı / sarmalayıcı yapı türü tanımına gerek yoktur:

instance7 := SomeType{
    SomeField: &(&struct{ x int64 }{7}).x,
}

1
bu, instanceiki farklı nesne iki farklı int64s'yi göstereceğinden , sorudaki yer tutuculu son örnekten işlevsel olarak farklıdır . Ancak OP'lerin amacını yeterince karşılıyor gibi görünüyor
Ryan Haining

2
bu kesinlikle sorumu cevaplıyor. Ama bu beni oldukça üzüyor: blog.golang.org/constants&[]int64{2}[0] adresindeki sabitlerin açıklamasına dayanarak bunun tam olarak çalışması gerektiğini düşünüyorum&0 .
ThisGuy

@RyanHaining Peki aynı adres atanmış gibi çalışırsa ne olur? İki farklı instancenesne aynı şeyi gösterirse int64ve biri sivri uçlu nesneyi değiştirirse, ikisi de değişir. Peki ya şimdi aynı kelimeyi 3. oluşturmak için kullanırsanız instance? Aynı adres şimdi farklı bir int64değere işaret edecektir ... bu nedenle farklı bir adres kullanılmalıdır, ancak o zaman neden ilk 2 durumunda aynısını kullanalım?
icza

@icza genellikle aynı nesneye işaret etmelerini istemezsiniz, yapacağınızı söylemiyorum. Ben sadece farkı işaret ediyorum.
Ryan Haining

4
@Conslo Sabitleri derleme zamanında değerlendirilir. Geçerli bir işaretçi değeri, geçerli bir bellek adresi yalnızca çalışma zamanında mevcuttur, dolayısıyla bu sabitlerle aynı değildir.
icza

5

Sorunu çözmek için int64 değişkeninin adresini döndüren bir işlev kullanın.

Aşağıdaki kodda f, bir tamsayıyı kabul eden ve tamsayının adresini tutan bir işaretçi değeri döndüren işlevi kullanıyoruz . Bu yöntemi kullanarak yukarıdaki sorunu kolayca çözebiliriz.

type myStr struct {
    url *int64
}

func main() {
    f := func(s int64) *int64 {
        return &s
    }
    myStr{
        url: f(12345),
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.