Spécification du langage Go : normes de programmation et de codage de haute qualité

1. Introduction

La programmation de haute qualité fait référence à l'utilisation de normes élevées et de bonnes pratiques pour écrire du code lisible, maintenable, testable et performant en termes de performances.

  • Les différentes conditions aux limites sont-elles complètement prises en compte ?
  • Gestion des exceptions et assurance de la stabilité
  • Facile à lire et à entretenir

(1) Principes de codage


Du point de vue des instructions, la manière de coder pendant le développement peut réduire le nombre d'instructions exécutées. Les différentes fonctionnalités et syntaxes du langage varient, mais les principes suivis par une programmation de haute qualité sont les mêmes, comme suit :

  1. Simplicité : le code doit être concis et clair, évitant la redondance et la logique complexe. Un code propre est plus facile à comprendre, à déboguer et à maintenir.
  2. Lisibilité : le code doit être facile à lire et à comprendre. Utilisez des noms de variables et de fonctions significatifs, suivez un style de codage cohérent et ajoutez des commentaires et une documentation appropriés pour améliorer la lisibilité du code.
  3. Cohérence : suivez des conventions de dénomination, un style de codage et une organisation du code cohérents lors de l'écriture du code. Un style de codage cohérent rend le code plus facile à comprendre et à maintenir.
  4. Modularisation : Divisez le code en modules ou fonctions, chaque module ou fonction n'est responsable que d'une tâche claire. Le code modulaire est plus facile à tester, à réutiliser et à maintenir.
  5. Gestion des erreurs : gérez les erreurs et les exceptions de manière appropriée. Évitez d'ignorer les erreurs et implémentez plutôt des mécanismes de gestion des erreurs appropriés, tels que le renvoi d'une valeur d'erreur ou l'émission d'une exception.
  6. Gestion des dépendances : utilisez les modules Go pour gérer les dépendances afin de garantir la reproductibilité et la maintenabilité du code. Vous pouvez utiliser les modules Go pour gérer les dépendances du projet.
  7. Tests : l'écriture de tests est un moyen important pour garantir la qualité du code. Écrivez des tests unitaires et des tests d'intégration pour couvrir diverses fonctions et cas extrêmes du code.
  8. Documentation : rédigez une documentation claire et précise, comprenant des commentaires sur le code, des descriptions de fonctions et la documentation du projet. Une bonne documentation aide les autres développeurs à comprendre et à utiliser le code.
  9. Sécurité de la concurrence : Dans un environnement multithread, il est nécessaire d'assurer la sécurité de la concurrence du code. Ceci peut être réalisé en utilisant des mécanismes tels que Mutex ou Channel fournis par le langage Go.

(2) Comment écrire du code Go de haute qualité


1. Format des codes

  • gofmt

gofmtIl s'agit d'un outil de ligne de commande officiellement fourni par le langage Go pour formater le code Go. Il ajuste automatiquement l'indentation, les espaces, les positions des crochets, etc. du code pour garantir la cohérence et la lisibilité du code.

À partir de la ligne de commande, vous pouvez utiliser la commande suivante pour exécuter gofmtl'outil :

gofmt -w <文件或目录>

Parmi eux, -wl'option signifie écrire le code formaté directement dans le fichier source. Si -wl'option n'est pas utilisée gofmt, le code formaté sera affiché sur la sortie standard.

Par exemple, pour formater main.goun fichier nommé, vous exécuterez la commande suivante :

gofmt -w main.go

Si vous souhaitez formater tous les fichiers Go dans l'ensemble du répertoire du projet, vous pouvez exécuter la commande suivante :

gofmt -w .

Il convient de noter que gofmtl'outil modifiera directement le fichier source, donc avant de l'exécuter, il est recommandé de sauvegarder le code pour éviter toute modification accidentelle.

De plus, vous pouvez également utiliser des plug-ins dans certains éditeurs ou IDE, tels que GoLand, le plug-in Go de Visual Studio Code, etc., pour déclencher automatiquement l'opération de formatage gofmtde l'outil. Cela peut formater automatiquement le code lors de l'enregistrement du fichier, améliorant encore l'efficacité du développement.

  • goimports

goimportsC'est aussi un outil officiellement fourni par le langage Go. Il ajoute une fonction d'importation automatique basée sur. En plus de formater le code, il détectera et ajoutera également automatiquement les instructions d'importation manquantes, supprimera les instructions d'importation inutilisées et triera et classifiera les instructions d'importation selon certaines règles. gofmtgoimports

2. Commentaires

En langage Go, les commentaires sont du texte utilisé pour décrire et expliquer le code. Le langage Go prend en charge deux types de commentaires : les commentaires sur une seule ligne et les commentaires sur plusieurs lignes.

  • Commentaires sur une seule ligne : //Commencer par, utilisé pour commenter une seule ligne de code ou une seule ligne d'instructions.
// 这是一个单行注释
fmt.Println("Hello, World!") // 打印Hello, World!
  • Commentaires multilignes : /*commencent par et */se terminent par, utilisés pour commenter du code multiligne ou des instructions multilignes.
/*
这是一个多行注释,
可以跨越多行。
*/
fmt.Println("Hello, World!")
  • En plus de décrire le code, les commentaires peuvent également être utilisés pour générer de la documentation. Dans le langage Go, la documentation peut être générée à l'aide de commentaires spécialement formatés, appelés commentaires de documentation ou annotations de documentation.

Les commentaires de documentation /*commencent par, */se terminent par et en ajoutent un avant chaque ligne de commentaire *. Les commentaires de documentation peuvent contenir des balises spéciales, telles que @param, @returnetc., pour décrire les paramètres et les valeurs de retour de la fonction.

/*
calculateSum函数用于计算两个整数的和。

@param a 第一个整数
@param b 第二个整数
@return 两个整数的和
*/
func calculateSum(a, b int) int {
    return a + b
}

Vous pouvez utiliser go docla commande pour afficher les commentaires de documentation dans votre code.

go doc <包名>.<函数名>

Par exemple, pour afficher calculateSumles commentaires de documentation pour une fonction, vous pouvez exécuter la commande suivante :

go doc <包名>.calculateSum

Les commentaires sont une partie importante de l’écriture d’un code clair et lisible. De bons commentaires peuvent aider d'autres développeurs à comprendre l'intention et la fonctionnalité du code et peuvent être utilisés pour générer une documentation de référence. Par conséquent, lors de l’écriture du code, il est recommandé d’utiliser des commentaires pour expliquer et illustrer la logique et les fonctionnalités du code.

3. Convention de dénomination

La dénomination est une partie importante des spécifications du code, et des règles de dénomination unifiées contribueront à améliorer la lisibilité du code.

Les noms Go commencent par les lettres de a à Z ou de a à Z ou un trait de soulignement, suivis de zéro ou plusieurs lettres, traits de soulignement et chiffres (0 à 9). Go n'autorise pas les signes de ponctuation tels que @, $ et % dans les noms.

  • Go est un langage de programmation sensible à la casse. Par conséquent, Manpower et Manpower sont deux noms différents.
  • Lorsque le nom (incluant les constantes, les variables, les types, les noms de fonctions, les champs de structure, etc.) commence par une lettre majuscule, telle que : Groupe1, alors les objets utilisant cette forme d'identifiant peuvent être utilisés par le code du package externe (client Le programme doit d'abord importer ce package), ce qui est appelé export (comme public dans les langages orientés objet) ;
  • Les noms commençant par une lettre minuscule ne sont pas visibles en dehors du package, mais ils sont visibles et disponibles dans l'ensemble du package (comme private dans les langages orientés objet)
Dénomination des variables

Semblables aux structures, les noms de variables suivent généralement la méthode de la casse chameau, et la première lettre est en majuscule ou en minuscule selon le principe du contrôle d'accès. Cependant, lorsque vous rencontrez des noms uniques, les règles suivantes doivent être suivies :

  • Si la variable est privée et que le nom unique est le premier mot, utilisez des minuscules, comme apiClient
  • Dans d'autres cas, la méthode d'écriture originale du nom doit être utilisée, telle que APIClient, repoID, UserID.
  • Exemple d'erreur : UrlArray, doit être écrit sous la forme urlArray ou URLArray
  • Si le type de variable est bool, le nom doit commencer par Has, Is, Can ou Allow
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
Dénomination de l'interface

Les règles de dénomination sont basiques et les types de structure ci-dessus. Le nom de structure d'une seule fonction est suffixé par "er", par exemple Reader, Writer.

type Reader interface {
        Read(p []byte) (n int, err error)
}
Dénomination du fichier

Essayez d'utiliser des noms de fichiers significatifs, courts, significatifs et contenant des mots minuscules , en utilisant des traits de soulignement pour séparer les mots individuels.

my_test.go
Nom du paquet : paquet

Gardez le nom du package et le répertoire cohérents, essayez d'utiliser des noms de package significatifs, soyez courts, significatifs et essayez de ne pas entrer en conflit avec la bibliothèque standard. Les noms de packages doivent être des mots minuscules et ne pas utiliser de traits de soulignement ou de casse mixte.

package demo

package main

4. Processus de contrôle

Le contrôle de flux est une partie importante de tout langage de programmation qui contrôle la direction logique et la séquence d'exécution.

Les contrôles de processus couramment utilisés dans le langage Go incluent if et for, tandis que switch et goto sont principalement des structures créées pour simplifier le code et réduire le code répétitif, et appartiennent au contrôle de processus de classe étendu.

  • Go语言if else(分支结构)

Dans le langage Go, le mot-clé if est une instruction utilisée pour tester une certaine condition (booléenne ou logique). Si la condition est vraie, le bloc de code entouré d'accolades {} après le if sera exécuté, sinon le bloc de code sera ignoré .

if condition {    
    // do something
}

S'il y a une deuxième branche, vous pouvez ajouter le mot-clé else et un autre bloc de code basé sur le code ci-dessus. Le code de ce bloc de code ne sera exécuté que lorsque la condition n'est pas remplie. Les deux blocs de code après if et else sont branches indépendantes, et une seule d’entre elles peut être exécutée.

if condition {
    // do something
} else {
    // do something
}

S'il existe une troisième branche, vous pouvez utiliser la forme suivante de trois branches indépendantes :

if condition1 {
    // do something
} else if condition2 {
    // do something 
} else {
    // catch-all or default
}

Il n'y a pas de limite au nombre de branches else if, mais pour des raisons de lisibilité du code, il est préférable de ne pas en ajouter trop après if. Si vous devez utiliser ce formulaire, mettez en premier les conditions qui sont satisfaites autant que possible.

  • Go语言switch case语句

L'expression n'a pas besoin d'être une constante ni même un entier. Les observations sont évaluées de haut en bas jusqu'à ce qu'une correspondance soit trouvée. Si le commutateur n'a pas d'expression, la correspondance est vraie.

Le langage Go a amélioré la conception syntaxique de switch. Case et case sont des blocs de code indépendants. Il n'est pas nécessaire de sortir du bloc de code de cas actuel via l'instruction break pour éviter l'exécution à la ligne suivante. L'exemple de code est le suivant :

var a = "hello"
switch a {
case "hello":
    fmt.Println(1)
case "world":
    fmt.Println(2)
default:    
    fmt.Println(0)}

//代码输出: 1

Dans l'exemple ci-dessus, chaque cas est au format chaîne et utilise la branche par défaut. Le langage Go stipule que chaque commutateur ne peut avoir qu'une seule branche par défaut.

  • Go语言for循环结构

Lorsque vous utilisez des instructions de boucle, vous devez faire attention aux points suivants :

  • L'accolade ouvrante { doit être sur la même ligne que pour.
  • La boucle for du langage Go est la même que celle du langage C, permettant de définir et d'initialiser des variables dans des conditions de boucle. La seule différence est que le langage Go ne prend pas en charge plusieurs instructions d'affectation séparées par des virgules. L'affectation parallèle doit être utilisée pour initialiser plusieurs affectations. variables.
  • La boucle for du langage Go prend également en charge continue et break pour contrôler la boucle, mais elle fournit un break plus avancé, qui peut choisir quelle boucle interrompre, comme dans l'exemple suivant :
for j := 0; j < 5; j++ {
    for i := 0; i < 10; i++ {
        if i > 5 {
            break JLoop        
        }        
        fmt.Println(i)
    }
}

JLoop:// ...

Dans le code ci-dessus, l'instruction break termine la boucle externe au niveau de l'étiquette JLoop.

5. Gestion des erreurs et des exceptions

Go adopte une approche différente des autres langages en matière de gestion des erreurs et des exceptions. La gestion des erreurs dans le langage Go se fait en renvoyant des valeurs d'erreur au lieu d'utiliser un mécanisme d'exception.

simple erreur
  • En langage Go, errors.New()les fonctions sont utilisées pour créer un nouvel objet d'erreur. Il reçoit un paramètre de chaîne comme informations de description de l'erreur et renvoie une valeur du type d'erreur. Déterminez le type d’erreur spécifique en évaluant l’instance de l’objet d’erreur.
err := errors.New("something error")
  • fmt.Errorf() Créer un objet d'erreur d'interface d'erreur
err := fmt.Errorf("发生了错误:%s", reason)

Vous pouvez imprimer la représentation sous forme de chaîne d'une valeur en appelant la fonction fmt.Printf et en donnant l'espace réservé %s. Pour les autres types de valeurs, tant que nous pouvons écrire une méthode String pour ce type, nous pouvons personnaliser sa représentation sous forme de chaîne.

Pour une valeur de type erreur, sa représentation sous forme de chaîne dépend de sa méthode Error. Dans le cas ci-dessus, si la fonction fmt.Printf constate que la valeur imprimée est une valeur de type erreur, elle appellera sa méthode Error. Ce type de fonction d'impression dans le package fmt fait réellement cela.

À propos, lorsque nous souhaitons générer des informations d'erreur via des modèles et obtenir la valeur d'erreur, nous pouvons utiliser la fonction fmt.Errorf. En réalité, cette fonction consiste à appeler d'abord la fonction fmt.Sprintf pour obtenir le message d'erreur exact, puis à appeler la fonction error.New pour obtenir la valeur du type d'erreur contenant le message d'erreur, et enfin à renvoyer la valeur.

Mauvais emballage et déballage

Dans le langage Go, le package d'erreurs de la bibliothèque standard fournit Wraples fonctions et Unwrap, qui font référence à l'empaquetage et au déballage des erreurs dans le mécanisme de gestion des erreurs.

  • L'enveloppement d'erreur fait référence à l'enveloppement de l'erreur d'origine dans une nouvelle erreur pour fournir plus d'informations contextuelles lors de la gestion des erreurs. Cela préserve les informations de pile de l'erreur d'origine et y associe la nouvelle erreur.
  • Le déballage des erreurs fait référence à l’extraction de l’erreur d’origine de l’erreur encapsulée. Cela vous permettra d'obtenir les détails de l'erreur d'origine si nécessaire.

Actuellement, les API fournies dans la bibliothèque standard Go pour l'encapsulage des erreurs incluent fmt.Errorf et erreurs.Join. fmt.Errorf est le plus couramment utilisé. fmt.Errorf prend également en charge le regroupement de plusieurs erreurs à la fois via plusieurs %ws. Voici un exemple complet :

func main() {
    err1 := errors.New("error1")
    err2 := errors.New("error2")
    err3 := errors.New("error3")

    err := fmt.Errorf("wrap multiple error: %w, %w, %w", err1, err2, err3)
    fmt.Println(err)
    e, ok := err.(interface{ Unwrap() []error })
    if !ok {
        fmt.Println("not imple Unwrap []error")
        return
    }
    fmt.Println(e.Unwrap())
}

L’exemple de sortie en cours d’exécution est le suivant :

wrap multiple error: error1, error2, error3
[error1 error2 error3]

Nous voyons que plusieurs erreurs enveloppées à la fois par fmt.Errorf sont affichées sur une seule ligne après avoir été converties en String.

errors.JoinUtilisé pour regrouper un ensemble d’erreurs en une seule erreur. Voici un exemple d’utilisation de error.Join pour regrouper plusieurs erreurs à la fois :

func main() {
    err1 := errors.New("error1")
    err2 := errors.New("error2")
    err3 := errors.New("error3")

    err := errors.Join(err1, err2, err3)
    fmt.Println(err)
    errs, ok := err.(interface{ Unwrap() []error })
    if !ok {
        fmt.Println("not imple Unwrap []error")
        return
    }
    fmt.Println(errs.Unwrap())
}

Le résultat de cet exemple est le suivant :

$go run demo2.go
error1
error2
error3
[error1 error2 error3]

Nous voyons qu'après que plusieurs erreurs encapsulées en même temps via error.Join soient converties en String, chaque erreur occupe une ligne distincte.

Mauvaise décision
  1. errors.Is(err, target): Déterminez errs'il s'agit d' targetune erreur de type et renvoyez une valeur booléenne. Cette fonction est utilisée pour déterminer si le type d'erreur correspond.
    if errors.Is(err, io.EOF) {
        fmt.Println("遇到了文件末尾")
    }
  2. errors.As(err, target) : Erreur errconvertie en targettype, renvoyant une valeur booléenne. Cette fonction est utilisée pour convertir les erreurs en types d'erreurs spécifiques et les gérer en conséquence.
    var n *net.OpError
    if errors.As(err, &n) {
        fmt.Println("遇到了网络错误:", n)
    }
Utilisation de la panique et de la récupération des exceptions

panique:

1. Fonction intégrée
2. Si une instruction de panique est écrite dans la fonction F, le code à exécuter ultérieurement sera terminé. S'il existe une liste de fonctions différées à exécuter dans la fonction F où se trouve la panique, elle sera exécuté dans l'ordre inverse du defer. 3. Retourner la fonction
F L'appelant G, dans G, le code après avoir appelé l'instruction de la fonction F ne sera pas exécuté. S'il y a une liste de fonctions defer à exécuter dans la fonction G, elle sera exécuté dans l'ordre inverse du defer. Le defer ici est quelque peu similaire à try-catch-finally. enfin
4. Jusqu'à ce que la goroutine se termine complètement et signale une erreur

récupérer:

1. Fonction intégrée
2. Utilisé pour contrôler le comportement de panique d'une goroutine et capturer la panique, affectant ainsi le comportement de l'application.
3. Suggestions d'appel générales
a) Dans la fonction de report, utilisez le récepteur pour mettre fin au processus de panique. d'une gojroutine et la restaurer. Exécution du code normal
b). Vous pouvez obtenir l'erreur passée par panique

Pour faire simple : Go peut lancer une exception de panique, puis capturer l'exception via la récupération en différé, puis la gérer normalement.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_53472334/article/details/132405439
conseillé
Classement