Table des matières
Go est généralement plus lent que le passage de la valeur
拷贝大的数据结构
可变性
API 一致性
表示缺失
utiliser des pointeurs ?
Maison développement back-end Golang Savez-vous quand utiliser les pointeurs Go ?

Savez-vous quand utiliser les pointeurs Go ?

Sep 24, 2021 pm 03:08 PM
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++. Savez-vous quand utiliser les pointeurs Go ?

Cet article explique comment utiliser correctement les pointeurs Go.

Mauvaise conclusion : utiliser des pointeurs est-il préférable ?

On pense généralement que les applications s'exécuteront plus rapidement lors de l'utilisation de pointeurs, car cela évitera de copier les valeurs à tout moment. Il n’est pas surprenant qu’au Go nous ayons la même idée.

Cependant, le passage du pointeur

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 commande go 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
Copier après la connexion
Si une variable ne s'échappe pas vers le tas, elle est sur la pile. La pile n'a pas besoin d'un ramasse-miettes pour effacer les variables, elle effectue uniquement des opérations 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"
}
Copier après la connexion

如果一个变量没有逃逸到堆中,它就在栈中。栈是不需要垃圾回收器来清除变量的,它只做 push/pop 操作。

如果任何内容都进行值传递,那么将一直在栈中做相关处理,这不会带来垃圾回收方面的开销。(GC 将按默认设置运行。堆中内容越少使得 GC 需要做的事情也越少)。

现在你知道了吧,使用指针反而会降低性能,那么什么时候需要使用指针呢?

拷贝大的数据结构

指针是否一直表现的比值传递差呢?显然不是这样的。对大的数据结构进行处理时,指针将发挥作用。这样可能会使得垃圾回收的开销被拷贝大量数据的开销抵消掉。

当我提到这点时,总是被问到‘那个大数据应该多大’?

我觉得这里没有一个固定的数值,凡是与性能相关的,都应该对其进行基准测试。 Go 有内置的强大的基准测试工具,完全可以利用起来  

可变性

唯一能修改函数参数的方式是传指针。默认对值的修改都是在副本上进行的。因此这些修改不能在调用它的函数中体现。

看下面的代码:

func main() {
 p := person{"Richard"}
 rename(&p)
 fmt.Println(p)
}func rename(p *person) {
 p.name = "test"
}
Copier après la connexion

输出是 Richard ,因为对 person 的修改是在它的副本上进行的。如果要改变底层 person 对象的值,需要使用指针。

func (p *person) rename(s string) {
   p.name = s 
}func (p *person) printName() {
  fmt.Println(p.name)
}
Copier après la connexion

如上,输出 test 。可变性是指针在 Go 中使用的一种情景。这是否是好事,还需要讨论。

API 一致性

使用指针可以维持最新值。这可以保持 API 一致性,即使不是所有的方法都改变它的值。

因此,这个:

func (p *person) rename(s string) {
   p.name = s 
}func (p person) printName() {
  fmt.Println(p.name)
}
Copier après la connexion

优于

type exam struct {
    score   int
    present bool
}
Copier après la connexion

虽然为了一致性并不需要在 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
}
Copier après la connexion
Copier après la connexion

使用单独的 presentMaintenant, vous savez, l'utilisation de pointeurs réduira les performances, alors quand

besoin

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)
Copier après la connexion
Copier après la connexion
🎜La sortie est 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
}
Copier après la connexion
Copier après la connexion

这也是 append 如何工作的,所以并不陌生。

x := []int{1,2}
x = append(x, 3)
x = append(x, 4)
Copier après la connexion
Copier après la connexion

鉴于指针的安全性,和值处理比指针处理更快,使用指针需要反复斟酌。

原文地址: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!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Vous avez un jeu croisé?
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

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

Comment envoyer des messages Go WebSocket ? Comment envoyer des messages Go WebSocket ? Jun 03, 2024 pm 04:53 PM

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}).

Comment faire correspondre les horodatages à l'aide d'expressions régulières dans Go ? Comment faire correspondre les horodatages à l'aide d'expressions régulières dans Go ? Jun 02, 2024 am 09:00 AM

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.

La différence entre la langue Golang et Go La différence entre la langue Golang et Go May 31, 2024 pm 08:10 PM

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.

Comment éviter les fuites de mémoire dans l'optimisation des performances techniques de Golang ? Comment éviter les fuites de mémoire dans l'optimisation des performances techniques de Golang ? Jun 04, 2024 pm 12:27 PM

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.

Analyse approfondie des pointeurs et des références en C++ pour optimiser l'utilisation de la mémoire Analyse approfondie des pointeurs et des références en C++ pour optimiser l'utilisation de la mémoire Jun 02, 2024 pm 07:50 PM

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.

Un guide pour les tests unitaires des fonctions simultanées Go Un guide pour les tests unitaires des fonctions simultanées Go May 03, 2024 am 10:54 AM

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.

Comment utiliser le wrapper d'erreur de Golang ? Comment utiliser le wrapper d'erreur de Golang ? Jun 03, 2024 pm 04:08 PM

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.

Comment créer une Goroutine priorisée dans Go ? Comment créer une Goroutine priorisée dans Go ? Jun 04, 2024 pm 12:41 PM

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.

See all articles