Le site Vector3.Normalize()
a une méthode pointeur donc, pour appeler cette méthode, un pointeur sur Vector3
est nécessaire ( *Vector3
). Dans votre premier exemple, vous stockez la valeur de retour de Vector3.Minus()
dans une variable, qui sera de type Vector3
.
Les variables dans Go sont adressables, et quand vous écrivez diff.Normalize()
il s'agit d'un raccourci, et le compilateur prendra automatiquement l'adresse de l'objet diff
pour avoir la valeur de récepteur requise de type *Vector3
afin d'appeler Normalize()
. Le compilateur va donc le "transformer" en
(&diff).Normalize()
Ceci est détaillé dans Spec : Appels :
Un appel de méthode x.m()
est valable si le méthode définie de (le type de) x
contient m
et la liste d'arguments peut être assignée à la liste de paramètres de m
. Si x
es adressable y &x
L'ensemble des méthodes de l'entreprise contient m
, x.m()
est un raccourci pour (&x).m()
.
La raison pour laquelle votre deuxième exemple ne fonctionne pas est que les valeurs de retour des appels de fonctions et de méthodes sont non adressable donc le compilateur n'est pas capable de faire la même chose ici, le compilateur n'est pas capable de prendre l'adresse de la valeur de retour de la fonction Vector3.Minus()
appeler.
Ce qui est adressable est exactement listé dans le Spec : Opérateurs d'adresse :
L'opérande doit être adressable Il s'agit soit d'une opération d'indexation de variable, de pointeur indirect ou de tranche, soit d'un sélecteur de champ d'un opérande de structure adressable, soit d'une opération d'indexation de tableau d'un tableau adressable. Exception à l'exigence d'adressabilité, x
[dans l'expression de &x
] peut également être un (éventuellement entre parenthèses) littéral composite .
Voir les questions connexes :
Comment obtenir le pointeur de la valeur de retour d'un appel de fonction ?
Comment puis-je stocker une référence au résultat d'une opération en Go ?
Solutions de contournement possibles
"La solution la plus simple (celle qui nécessite le moins de modifications) consiste simplement à assigner une variable et à appeler la méthode après cela. C'est votre première solution fonctionnelle.
Une autre façon est de modifier les méthodes pour avoir un récepteur de valeur (au lieu d'un récepteur de pointeur), de sorte qu'il n'est pas nécessaire de prendre l'adresse des valeurs de retour des méthodes, de sorte que les appels peuvent être "enchaînés". Notez que cela peut ne pas être viable si une méthode a besoin de modifier le récepteur, car cela n'est possible que si c'est un pointeur (car le récepteur est passé comme n'importe quel autre paramètre - en faisant une copie -, et si ce n'est pas un pointeur, vous ne pourriez que modifier la copie).
Une autre façon de procéder consiste à modifier les valeurs de retour pour qu'elles renvoient des pointeurs ( *Vector3
) au lieu de Vector3
. Si la valeur de retour est déjà un pointeur, il n'est pas nécessaire de prendre son adresse car elle est bonne en l'état pour le récepteur d'une méthode qui nécessite un pointeur récepteur.
Vous pouvez également créer une fonction d'aide simple qui renvoie son adresse. Cela pourrait ressembler à quelque chose comme ceci :
func pv(v Vector3) *Vector3 {
return &v
}
L'utiliser :
dir := pv(projected.Minus(c.Origin)).Normalize()
Cela pourrait aussi être une méthode de Vector3
par exemple :
func (v Vector3) pv() *Vector3 {
return &v
}
Et ensuite l'utiliser :
dir := projected.Minus(c.Origin).pv().Normalize()
Quelques notes :
Si votre type est composé de 3 float64
seulement, vous ne devriez pas voir de différences de performance significatives. Mais vous devez être cohérent quant à vos types de récepteurs et de résultats. Si la plupart de vos méthodes ont des récepteurs à pointeur, elles doivent toutes en avoir. Si la plupart de vos méthodes renvoient des pointeurs, elles doivent toutes le faire.