Il est très peu clair pour moi dans quel cas je voudrais utiliser un récepteur de valeur au lieu de toujours utiliser un récepteur de pointeur.
Pour récapituler à partir des documents:
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
La documentation dit également "Pour les types tels que les types de base, les tranches et les petites structures, un récepteur de valeur est très bon marché donc à moins que la sémantique de la méthode ne nécessite un pointeur, un récepteur de valeur est efficace et clair."
Premier point, il dit qu'il est "très bon marché", mais la question est plus est-il moins cher que le récepteur de pointeur. J'ai donc fait un petit benchmark (code sur l'essentiel) qui m'a montré que le récepteur de pointeur est plus rapide même pour une structure qui n'a qu'un seul champ de chaîne. Voici les résultats:
// Struct one empty string property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 500000000 3.62 ns/op
// Struct one zero int property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 2000000000 0.36 ns/op
(Modifier: veuillez noter que le deuxième point est devenu invalide dans les nouvelles versions de go, voir les commentaires) .
Deuxième point dit-il, c'est "efficace et clair", ce qui est plus une question de goût, n'est-ce pas? Personnellement, je préfère la cohérence en utilisant partout de la même manière. Efficacité dans quel sens? en termes de performances, il semble que les pointeurs soient presque toujours plus efficaces. Peu de tests avec une propriété int ont montré un avantage minimal du récepteur Value (plage de 0,01-0,1 ns / op)
Quelqu'un peut-il me dire un cas où un récepteur de valeur a clairement plus de sens qu'un récepteur de pointeur? Ou est-ce que je fais quelque chose de mal dans le benchmark, ai-je négligé d'autres facteurs?
Réponses:
Notez que la FAQ mentionne la cohérence
Comme mentionné dans ce fil :
Maintenant:
Le commentaire de révision de code peut aider:
La partie en gras se trouve par exemple dans
net/http/server.go#Write()
:la source
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers
Pas vrai, en fait. Les méthodes de récepteur de valeur et de récepteur de pointeur peuvent être appelées sur un pointeur ou un non-pointeur correctement typé. Indépendamment de ce sur quoi la méthode est appelée, dans le corps de la méthode, l'identifiant du récepteur fait référence à une valeur par copie lorsqu'un récepteur de valeur est utilisé, et à un pointeur lorsqu'un récepteur de pointeur est utilisé: Voir play.golang.org/p / 3WHGaAbURMInt(5).increment_by_one_ptr()
. De même, un trait qui définit la méthodeincrement_by_one_ptr
ne sera pas satisfait d'une valeur de typeInt
.Pour ajouter en plus à @VonC une excellente réponse informative.
Je suis surpris que personne n'ait vraiment mentionné le coût de maintenance une fois que le projet s'agrandit, que les anciens développeurs partent et que le nouveau arrive. Go est sûrement une langue jeune.
De manière générale, j'essaie d'éviter les pointeurs quand je le peux, mais ils ont leur place et leur beauté.
J'utilise des pointeurs lorsque:
Par exemple:
Raisons pour lesquelles j'évite les pointeurs:
Ma règle d'or, écrivez autant de méthodes encapsulées que possible, telles que:
METTRE À JOUR:
Cette question m'a inspiré à approfondir mes recherches sur le sujet et à écrire un article de blog à ce sujet https://medium.com/gophersland/gopher-vs-object-oriented-golang-4fa62b88c701
la source