Savez-vous quand utiliser les pointeurs Go ?
Cet article est fourni par la rubrique go languagetutoriel pour vous présenter dans quelles circonstances utiliser Go pointer (Go Pointer).
Je pense que l'un des plus gros malentendus lors de l'utilisation des pointeurs est que les pointeurs en Go sont très similaires aux pointeurs en C. Cependant, ce n’est pas le cas. Les pointeurs ne fonctionnent pas en Go de la même manière qu’en C/C++.
Go est généralement plus lent que le passage de la valeur
. C'est une conséquence du fait que Go est un langage ramassé. Lorsque vous transmettez un pointeur vers une fonction, Go doit effectuer une analyse d'échappement pour déterminer si la variable doit être stockée sur le tas ou sur la pile. Cela ajoute déjà une surcharge supplémentaire, mais sinon les variables peuvent être stockées dans le tas. Lorsque vous stockez une variable dans le tas, vous perdez également du temps pendant l'exécution du GC. Une fonctionnalité pratique de Go est que vous pouvez vérifier ce que l'analyse d'échappement a fait en exécutant la commandego build -gcflags="-m"
. Si vous faites cela, Go vous dira si une variable s'échappe vers le tas :
./main.go:44:20: greet ... argument does not escape ./main.go:44:21: greeting escapes to heap ./main.go:44:21: name escapes to heap
push/pop
. Si un contenu est transmis par valeur, il sera toujours traité sur la pile, ce qui n'entraînera pas de surcharge de garbage collection. (Le GC s'exécutera par défaut. Moins de contenu dans le tas signifie que le GC a moins à faire). go build -gcflags="-m"
来检查逃逸分析做了什么。如果你这样做,Go 将告诉你一个变量是否逃到堆上:
type person struct { name string }func main() { p := person{"Richard"} rename(p) fmt.Println(p) }func rename(p person) { p.name = "test" }
如果一个变量没有逃逸到堆中,它就在栈中。栈是不需要垃圾回收器来清除变量的,它只做 push/pop
操作。
如果任何内容都进行值传递,那么将一直在栈中做相关处理,这不会带来垃圾回收方面的开销。(GC 将按默认设置运行。堆中内容越少使得 GC 需要做的事情也越少)。
现在你知道了吧,使用指针反而会降低性能,那么什么时候需要使用指针呢?
拷贝大的数据结构
指针是否一直表现的比值传递差呢?显然不是这样的。对大的数据结构进行处理时,指针将发挥作用。这样可能会使得垃圾回收的开销被拷贝大量数据的开销抵消掉。
当我提到这点时,总是被问到‘那个大数据应该多大’?
我觉得这里没有一个固定的数值,凡是与性能相关的,都应该对其进行基准测试。 Go 有内置的强大的基准测试工具,完全可以利用起来
可变性
唯一能修改函数参数的方式是传指针。默认对值的修改都是在副本上进行的。因此这些修改不能在调用它的函数中体现。
看下面的代码:
func main() { p := person{"Richard"} rename(&p) fmt.Println(p) }func rename(p *person) { p.name = "test" }
输出是 Richard
,因为对 person 的修改是在它的副本上进行的。如果要改变底层 person 对象的值,需要使用指针。
func (p *person) rename(s string) { p.name = s }func (p *person) printName() { fmt.Println(p.name) }
如上,输出 test
。可变性是指针在 Go 中使用的一种情景。这是否是好事,还需要讨论。
API 一致性
使用指针可以维持最新值。这可以保持 API 一致性,即使不是所有的方法都改变它的值。
因此,这个:
func (p *person) rename(s string) { p.name = s }func (p person) printName() { fmt.Println(p.name) }
优于
type exam struct { score int present bool }
虽然为了一致性并不需要在 printName
中使用指针。但是这将使得 API 更简单,避免去记到底哪里需要引用。
表示缺失
一般值在使用时,具有默认零值。但有些情景需要知道某个事物是缺少或未填充值。例如一个结构体包含学生的考试分数,如果结构体是空且有分数 0 ,这表示这个学生考的不好,还是压根没有参加考试呢?
指针的默认零值是 nil
指针,表示没有设置值。也可以像下面这样实现这种要求:
func main() { p := person{"richard"} p = rename(p) fmt.Println(p) }func rename(p person) person { p.name = "test" return p }
使用单独的 present
Maintenant, vous savez, l'utilisation de pointeurs réduira les performances, alors quand
utiliser des pointeurs ?
Copie de grandes structures de donnéesLes pointeurs fonctionnent-ils toujours moins bien que le transfert de valeur ? Ce n'est évidemment pas le cas. Lorsqu’il s’agit de grandes structures de données, les pointeurs entrent en jeu. Cela peut entraîner une compensation du coût du garbage collection par le coût de la copie de grandes quantités de données.
Quand je mentionne cela, on me demande toujours « quelle devrait être la taille de ce big data » ?
Je pense qu'il n'y a pas de valeur fixe ici, tout ce qui concerne la performance doit être comparé. Go dispose de puissants outils d'analyse comparative intégrés, qui peuvent être pleinement exploités
🎜Variabilité🎜🎜La seule façon de modifier les paramètres d'une fonction est de transmettre des pointeurs. Par défaut, les modifications des valeurs sont effectuées sur la copie. Ces modifications ne peuvent donc pas être répercutées dans la fonction qui l'appelle. 🎜🎜Regardez le code ci-dessous : 🎜x := []int{1,2} x = append(x, 3) x = append(x, 4)
Richard
car les modifications apportées à la personne sont apportées sur sa copie. Si vous souhaitez modifier la valeur de l'objet personne sous-jacent, vous devez utiliser un pointeur. 🎜rrreee🎜Comme ci-dessus, affichez test
. La mutabilité est une situation dans laquelle des pointeurs sont utilisés dans Go. La question de savoir si c’est une bonne chose est à débattre. 🎜🎜Cohérence de l'API🎜🎜Utilisez des pointeurs pour conserver la dernière valeur. Cela permet de maintenir la cohérence de l'API même si toutes les méthodes ne modifient pas sa valeur. 🎜🎜Donc, ceci : 🎜rrreee🎜 est meilleur que 🎜rrreee🎜 bien que pour des raisons de cohérence, il n'est pas nécessaire d'utiliser des pointeurs dans printName
. Mais cela simplifiera l’API et évitera d’avoir à se rappeler où exactement une référence est nécessaire. 🎜🎜 indique qu'il manque 🎜🎜Les valeurs générales, lorsqu'elles sont utilisées, ont une valeur par défaut de zéro. Mais il existe des scénarios dans lesquels vous devez savoir que quelque chose manque ou a une valeur non renseignée. Par exemple, une structure contient le résultat d'un test d'un élève. Si la structure est vide et a un score de 0, cela signifie-t-il que l'étudiant n'a pas bien réussi le test ou qu'il n'a pas passé le test du tout ? 🎜🎜La valeur zéro par défaut d'un pointeur est un pointeur nil
, ce qui signifie qu'aucune valeur n'est définie. Cette exigence peut également être mise en œuvre comme suit : 🎜rrreee🎜Utilisez un champ présent
distinct pour indiquer que l'étudiant n'a pas passé l'examen. 🎜🎜Pourquoi ai-je choisi la valeur ? 🎜🎜🎜C'est quelque peu subjectif. Différentes personnes ont des compréhensions différentes de la programmation, nous n'exigeons donc pas que tout le monde ait le même concept🎜🎜🎜Je pense qu'il est logique d'avoir autant que possible des valeurs par défaut dans les valeurs Go. Cela ne s’applique peut-être pas à tous les scénarios, mais dans mon cas, cela a évité un gros accident. L’utilisation d’une valeur au lieu d’un pointeur ne provoquera pas « l’erreur d’un million de dollars » de Tony Hoare en raison d’un pointeur nul. 🎜🎜La valeur par défaut de zéro est utile pour éviter beaucoup de déclarations. 🎜另一个好处是易变性造成的问题比它解决的问题多的得多。易变性给函数带来的副作用同时使得调试变得更加困难。 通过让函数返回修改之后的结构体,可以避免这种突变。
重写之前的例子
func main() { p := person{"richard"} p = rename(p) fmt.Println(p) }func rename(p person) person { p.name = "test" return p }
这也是 append
如何工作的,所以并不陌生。
x := []int{1,2} x = append(x, 3) x = append(x, 4)
鉴于指针的安全性,和值处理比指针处理更快,使用指针需要反复斟酌。
原文地址:https://medium.com/@meeusdylan/when-to-use-pointers-in-go-44c15fe04eac
译文地址:https://learnku.com/go/t/60923
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Dans Go, les messages WebSocket peuvent être envoyés à l'aide du package gorilla/websocket. Étapes spécifiques : Établissez une connexion WebSocket. Envoyer un message texte : appelez WriteMessage(websocket.TextMessage,[]byte("message")). Envoyez un message binaire : appelez WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}).

Dans Go, vous pouvez utiliser des expressions régulières pour faire correspondre les horodatages : compilez une chaîne d'expression régulière, telle que celle utilisée pour faire correspondre les horodatages ISO8601 : ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ . Utilisez la fonction regexp.MatchString pour vérifier si une chaîne correspond à une expression régulière.

Go et le langage Go sont des entités différentes avec des caractéristiques différentes. Go (également connu sous le nom de Golang) est connu pour sa concurrence, sa vitesse de compilation rapide, sa gestion de la mémoire et ses avantages multiplateformes. Les inconvénients du langage Go incluent un écosystème moins riche que les autres langages, une syntaxe plus stricte et un manque de typage dynamique.

Les fuites de mémoire peuvent entraîner une augmentation continue de la mémoire du programme Go en : fermant les ressources qui ne sont plus utilisées, telles que les fichiers, les connexions réseau et les connexions à la base de données. Utilisez des références faibles pour éviter les fuites de mémoire et ciblez les objets pour le garbage collection lorsqu'ils ne sont plus fortement référencés. En utilisant go coroutine, la mémoire de la pile de coroutines sera automatiquement libérée à la sortie pour éviter les fuites de mémoire.

En utilisant des pointeurs et des références, l'utilisation de la mémoire en C++ peut être optimisée : Pointeurs : stockent les adresses d'autres variables et peuvent pointer vers différentes variables, économisant de la mémoire, mais peuvent générer des pointeurs sauvages. Référence : alias vers une autre variable, pointe toujours vers la même variable, ne génère pas de pointeurs sauvages et convient aux paramètres de fonction. L'optimisation de l'utilisation de la mémoire peut améliorer l'efficacité et les performances du code en évitant les copies inutiles, en réduisant les allocations de mémoire et en économisant de l'espace.

Les tests unitaires des fonctions simultanées sont essentiels car cela permet de garantir leur comportement correct dans un environnement simultané. Des principes fondamentaux tels que l'exclusion mutuelle, la synchronisation et l'isolement doivent être pris en compte lors du test de fonctions concurrentes. Les fonctions simultanées peuvent être testées unitairement en simulant, en testant les conditions de concurrence et en vérifiant les résultats.

Dans Golang, les wrappers d'erreurs vous permettent de créer de nouvelles erreurs en ajoutant des informations contextuelles à l'erreur d'origine. Cela peut être utilisé pour unifier les types d'erreurs générées par différentes bibliothèques ou composants, simplifiant ainsi le débogage et la gestion des erreurs. Les étapes sont les suivantes : Utilisez la fonction error.Wrap pour envelopper les erreurs d'origine dans de nouvelles erreurs. La nouvelle erreur contient des informations contextuelles de l'erreur d'origine. Utilisez fmt.Printf pour générer des erreurs encapsulées, offrant ainsi plus de contexte et de possibilités d'action. Lors de la gestion de différents types d’erreurs, utilisez la fonction erreurs.Wrap pour unifier les types d’erreurs.

Il y a deux étapes pour créer un Goroutine prioritaire dans le langage Go : enregistrer une fonction de création de Goroutine personnalisée (étape 1) et spécifier une valeur de priorité (étape 2). De cette façon, vous pouvez créer des Goroutines avec des priorités différentes, optimiser l'allocation des ressources et améliorer l'efficacité de l'exécution.
