J'ai un type struct avec un *int64
champ.
type SomeType struct {
SomeField *int64
}
À un moment donné dans mon code, je veux déclarer un littéral de ce (par exemple, quand je sais que ladite valeur doit être 0, ou en pointant sur 0, vous voyez ce que je veux dire)
instance := SomeType{
SomeField: &0,
}
... sauf que ça ne marche pas
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value
Alors j'essaye ça
instance := SomeType{
SomeField: &int64(0),
}
... mais ça ne marche pas non plus
./main.go:xx: cannot take the address of int64(0)
Comment puis-je faire cela? La seule solution que je peux trouver est d'utiliser une variable d'espace réservé
var placeholder int64
placeholder = 0
instance := SomeType{
SomeField: &placeholder,
}
Noter la Edit: non ce n'est pas le cas. Désolé pour ça.&0
La syntaxe fonctionne très bien quand il s’agit d’un * int au lieu d’un *int64
.
Modifier:
Apparemment, il y avait trop d'ambiguïté dans ma question. Je cherche un moyen de littéralement a *int64
. Cela pourrait être utilisé dans un constructeur, ou pour énoncer des valeurs de structure littérales, ou même comme arguments à d'autres fonctions. Mais les fonctions d'assistance ou l'utilisation d'un type différent ne sont pas des solutions que je recherche.
La spécification de langue Go ( opérateurs d'adresse ) ne permet pas de prendre l'adresse d'une constante numérique (pas d'un non typé ni d'un typé constante).
L'opérande doit être adressable, c'est-à-dire une opération de variable, d'indirection de pointeur ou d'indexation de tranche. ou un sélecteur de champ d'un opérande struct adressable; ou une opération d'indexation de tableau d'un tableau adressable. En tant qu'exception à l'exigence d'adressabilité,
x
[dans l'expression de&x
] Peut également être un (éventuellement entre parenthèses) littéral composite .
Pour savoir pourquoi ceci n'est pas autorisé, voir la question connexe: Trouver l'adresse de la constante dans go . Une question similaire (non autorisée à prendre son adresse): Comment puis-je stocker une référence au résultat d'une opération dans Go?
Vos options (essayez tout sur le Go Playground ):
new()
Vous pouvez simplement utiliser la fonction intégrée new()
pour allouer un nouveau int64
À valeur zéro et obtenir son adresse:
instance := SomeType{
SomeField: new(int64),
}
Mais notez que cela ne peut être utilisé que pour allouer et obtenir un pointeur sur la valeur zéro de n'importe quel type.
Le plus simple et recommandé pour les éléments non nuls est d'utiliser une variable d'assistance dont l'adresse peut être prise:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
Ou si vous en avez besoin plusieurs fois, vous pouvez créer une fonction d'assistance qui alloue et retourne un *int64
:
func create(x int64) *int64 {
return &x
}
Et en l'utilisant:
instance3 := SomeType{
SomeField: create(3),
}
Notez que nous n’avons réellement alloué aucune ressource, le compilateur Go l’a fait lorsque nous avons renvoyé l’adresse de l’argument de la fonction. Le compilateur Go effectue une analyse d'échappement et alloue des variables locales sur le tas (au lieu de la pile) si elles risquent d'échapper à la fonction. Pour plus de détails, voir Est-ce que le retour d'une tranche d'un tableau local dans une fonction Go est sans danger?
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Ou comme alternative (plus courte):
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
Si vous voulez que *SomeField
Soit différent de 0
, Vous avez besoin de quelque chose d'adressable.
Vous pouvez toujours le faire, mais c'est moche:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
Ce qui se passe ici est une tranche []int64
Est créée avec un littéral, ayant un élément (5
). Et il est indexé (0ème élément) et l'adresse du 0ème élément est prise. En arrière-plan, un tableau de [1]int64
Sera également alloué et utilisé comme tableau de sauvegarde pour la tranche. Donc, il y a beaucoup de passe-partout ici.
Examinons l'exception aux exigences d'adressabilité:
En tant qu'exception à l'exigence d'adressabilité,
x
[dans l'expression de&x
] Peut également être un (éventuellement entre parenthèses) littéral composite .
Cela signifie que prendre l'adresse d'un littéral composite, par ex. un littéral struct est ok. Si nous le faisons, nous aurons la valeur de structure allouée et un pointeur obtenu. Mais si tel est le cas, une autre exigence nous sera disponible: "sélecteur de champ d'un opérande struct adressable" . Donc, si le littéral struct contient un champ de type int64
, Nous pouvons aussi prendre l'adresse de ce champ!
Voyons cette option en action. Nous allons utiliser ce type de structure wrapper:
type intwrapper struct {
x int64
}
Et maintenant on peut faire:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Notez que cela
&(&intwrapper{6}).x
signifie ce qui suit:
& ( (&intwrapper{6}).x )
Mais nous pouvons omettre la parenthèse "externe" car l'opérateur d'adresse &
Est appliqué au résultat de expression de sélecteur .
Notez également qu'en arrière-plan, les événements suivants se produiront (il s'agit également d'une syntaxe valide):
&(*(&intwrapper{6})).x
Le principe est le même que dans le cas n ° 6, mais nous pouvons également utiliser un littéral struct anonyme, aussi aucune définition de type struct helper/wrapper n'est nécessaire:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}
Dans le code ci-dessous, nous utilisons une fonction f qui accepte un entier et renvoie une valeur de pointeur contenant l'adresse du entier. En utilisant cette méthode, nous pouvons facilement résoudre le problème ci-dessus.
type myStr struct {
url *int64
}
func main() {
f := func(s int64) *int64 {
return &s
}
myStr{
url: f(12345),
}
}