Maison > développement back-end > Golang > le corps du texte

C'est tout ce que j'ai appris sur Go en DEUX semaines !

Barbara Streisand
Libérer: 2024-10-31 04:27:02
original
710 Les gens l'ont consulté

This is all what I

Quelle est votre approche lorsque vous avez besoin d'apprendre quelque chose de nouveau ? J'en ai un bien spécifique et encore une fois je l'ai testé en apprenant le Golang !

Il y a trop de contenu pour en parler, mais mon objectif ici est de lister des choses que j'ai trouvées utiles et que j'ai spécifiquement pris le temps de bien apprendre.

Table des matières

  • 1. Prologue
  • 2. Rencontrez la CLI
    • CLI 2.1 : passer au mod
    • CLI 2.2 : allez courir
  • 3. Comparaison de différentes syntaxes
    • Syntaxe 3.1 : Classes/Structs et encapsulation API
    • 3.2 Syntaxe : l'implémentation de l'interface est ÉTRANGE COMME FUC*
  • 4. Stdlib : définitivement une boîte à outils IMPRESSIONNANTE
    • 4.1 Packages : types primitifs
    • 4.2 Forfaits : trucs utiles
  • 5. Les tests dans Go sont SI SIMPLES
    • Tests 5.1 : tests de base
    • 5.2 Tests : Jetbrains Boilerplate
    • 5.3 Tests : exécution de tests
  • 6. Attention aux importations cycliques
  • 7. Différer ceci, différer cela... Mais qu'est-ce qu'un Différer ?
  • 8. Gestion des erreurs pour les Noobs
  • 9. Exploit de conclusion : défi de codage à faible latence

1. Prologue

Au cours des 2 dernières semaines, j'ai appris et créé de petites applications avec Golang. Pour le moment, cela fait presque 50 heures de code à travers de nombreux livestreams et ça a été plutôt génial d'apprendre quelque chose que j'avais auparavant quelques petits problèmes avec le langage.

Au cours de ce voyage de deux semaines, j'ai conçu :

  • Une petite coque VRAIMENT simple
  • Une implémentation Redis Basic
  • Mise en œuvre du protocole HTTP 1.1
  • Une implémentation de serveur DNS
  • et un test d'emploi pour une entreprise vraiment cool (qui sera disponible à la fin de cet article).

Et tout ça parce que mon patron m'a demandé, une fois de plus, d'apprendre une nouvelle technologie pour travailler sur des PoC et des démos ScyllaDB... Je n'étais pas trop content de la décision, mais bon, c'est mon travail.

Au cours de la dernière année, j'ai étudié Rust, et c'est probablement encore trop complexe pour moi, mais j'ai appris des concepts vraiment sympas qui ont fait que mon passage à Go fonctionne à merveille !

Dans cet article, je vais vous donner quelques astuces et conseils pour accélérer votre flux d'apprentissage.

2. Rencontrez la CLI

Je suis un développeur PHP et je suis habitué à la MEILLEURE CLI jamais créée (oui, c'est Artisan), mais au cours de mon parcours en tant que développeur, j'ai vécu des projets géniaux dont beaucoup ont été .. :

  • Cargo (Rouille)
  • NPM (JS)
  • Compositeur (PHP)
  • et ainsi de suite...

Quand je suis arrivé à l'environnement Go, cela a commencé comme un réel problème. Au moins pour moi, l'expérience développeur de Golang en termes d'outils et de documentation pourrait être bien meilleure. En y réfléchissant, j'ai décidé de passer en revue 3 commandes que vous DEVEZ APPRENDRE au début.

Rappelez-vous : ceci n'est qu'une présentation pas à pas avec ma propre explication des choses. Si vous souhaitez des informations détaillées, ouvrez la documentation :)
Aussi : allez dans la documentation, c'est nul, s'il vous plaît, quelqu'un y met un surligneur de syntaxe

CLI 2.1 : passer au module

Selon que vous souhaitiez modulariser votre application ou avoir un environnement organisé, ce sera la commande la plus utile au début.

La commande go mod gère toutes les dépendances au sein de votre projet et s'occupe également de supprimer automatiquement tout ce qui n'est plus utilisé.

Tout d'abord, dans votre nouveau dossier vide, initions un nouveau module dans le projet avec go mod init :

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cela créera un nouveau fichier à la racine du projet appelé go.mod, qui correspond essentiellement au contenu actuel :

  • Le nom du module
  • Votre version Go

Voici le fichier, si vous souhaitez le vérifier vous-même :

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Après cela, la prochaine chose que j'ai vraiment aimé était le mod go spice, qui ajoute essentiellement toutes les dépendances manquantes et supprime celles inutilisées.

go mod tidy
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ce deuxième est juste pour garder à l'esprit que cela existe et qu'il est vraiment utile ! Votre environnement l'exécutera probablement à CHAQUE FOIS et vous vous habituerez à voir les importations disparaître :p

2.2 CLI : allez courir

C'est probablement la commande la plus courante que vous utiliserez, puisque vous DEVEZ exécuter votre projet, mais voici comment cela fonctionne :

  • Vous devez pointer vers le fichier qui contient la fonction main().
  • Ce fichier ne doit pas nécessairement se trouver à la racine de votre dossier.

La chose la plus importante à retenir à propos de cette commande est que lorsque vous exécutez la commande go run, elle recherchera le fichier go.mod dans votre répertoire actuel et l'utilisera comme base pour mapper l'ensemble de votre projet (importations, packages , etc). Voici quelques exemples :

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Voici notre contenu app.go :

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

Copier après la connexion
Copier après la connexion
Copier après la connexion

Vous connaissez désormais les bases pour exécuter un projet ! Littéralement, bonjour tout le monde !

3. Comparaison de différentes syntaxes :

Mon problème avec Go a toujours été la façon dont il est écrit, mais après des heures de codage, j'ai réalisé que c'était plus simple que je ne le pensais. Comme vous l'avez peut-être deviné, j'ai une solide expérience en PHP et une certaine expérience avec Rust.

Quand j'ai commencé à apprendre Rust en 2023, heureusement, un gars dont je suis un grand fan, Nuno Maduro (Laravel), a donné une conférence intitulée "PHP for Rust Developers", qui m'a donné une introduction de base à la syntaxe et m'a donné un peu de répit pendant que j'étais complètement STOMPED par Rust.

En tout cas, ça m'a été utile à l'époque, alors pourquoi ne pas faire quelques comparaisons ?

3.1 Syntaxe : classes/structures et encapsulation API

En POO, nous avons des cours, ce qui est une façon vraiment sympa de résumer votre code en petits morceaux, et vous avez quelque chose de "comme ça". Golang peut être considéré comme une odyssée, car il peut s'agir d'un développement épique pour transformer l'environnement en ce que vous voulez qu'il soit.

Rappelez-vous, Golang est un « langage de haut niveau » qui fournit une syntaxe de « niveau système » qui vous permet de travailler facilement avec des implémentations de « bas niveau ».

Sous la syntaxe Go, vous pouvez

  • [Struct] Définissez une structure en la préfixant avec type, en ajoutant votre nom "class/struct", puis en ajoutant un suffixe de struct.
  • [Encapsulation] Définissez l'exposition des éléments liés à votre classe/structure en les commençant par des noms UpperCase ou LowerCase.
    • [Visibilité : "public"] : définissez le nom de l'élément en majuscule.
    • [Visibilité : "privé/protégé"] : définissez le nom de l'élément en minuscules.

Et vous pouvez l'utiliser pour : Structs, champs Struct, méthodes Struct. Regardez de plus près :

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans Rust, vous avez une approche plus explicite (plus de langages de type oop) où :

  • [Struct] Définissez une structure en utilisant le préfixe struct, en ajoutant votre nom "Class/Struct" et c'est tout.
  • [Encapsulation] Si vous souhaitez que quelque chose soit public sur d'autres "crates", vous devez ajouter le préfixe pub dans la partie du code que vous souhaitez exposer.
# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

J'aimerais rendre les choses explicites comme PHP, Java et ainsi de suite, mais si vous arrêtez de penser, c'est MOINS DE CODE à écrire, mais cela a également un impact sur la lisibilité.

3.2 Syntaxe : l'implémentation de l'interface est ÉTRANGE COMME FUC*

Pour être vraiment honnête, je suis le genre de personne qui essaierait de mettre, je ne sais pas... LARAVEL dans Go Environment, mais cela a déjà été fait dans Goravel. Quoi qu'il en soit, j'aime beaucoup l'idée de travailler avec "Interface/Contract Driven Development", et pour la première fois, je me suis retrouvé coincé avec cela dans un langage.

Dans Go, les interfaces ne sont pas "implémentées" dans une structure/classe, et pour un gars de POO comme moi, c'est tout simplement fou d'avoir une telle décision de conception dans ma tête. Jetez un œil à ce qui est attendu :

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant, quand il s'agit de partir : vous n'avez pas cette implémentation explicite d'une "interface" à l'intérieur d'une structure, et c'est, hmm... bizarre ? Au lieu de cela, vous implémentez simplement les méthodes requises par l'interface, qui vont vous vérifier au moment de la compilation. Il est juste de savoir qu'il s'agit d'un langage compilé et que cela ne devrait jamais poser de problème, mais je parle de mon point de vue avec Developer Experience !

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans tous les cas, avec un peu de temps à coder dans le langage vous vous y habituerez. Parlons maintenant de ce que l'environnement de base vous propose sans rien télécharger !

4. Stdlib : définitivement une boîte à outils IMPRESSIONNANTE

Maintenant, je parle de tout ce que Go vous sert avec la Bibliothèque standard, sans télécharger de package tiers. Voici une chronologie pour vous :

  • 1er jour : QUOI ? POURQUOI NE PAS AIMER JS/Java DANS LA AFFAIRE QUE LE TYPE PORTE TOUTES LES MÉTHODES ? (Et je les déteste tous les deux)
  • 1ère semaine :Attends, c'est peut-être une bonne merde (après avoir compris les packages pour les types primitifs)
  • 2ème semaine : QUOI ? POURQUOI LES AUTRES LANGUES N'ONT-ELLES PAS D'AUSSI BONNES BIBLIOTHÈQUES PAR DÉFAUT ?

Je ne plaisante pas avec ça, chaque jour que j'explore, je trouve une bibliothèque sympa parmi les bibliothèques standards. Alors, commençons par parler des types primitifs.

4.1 Packages : types primitifs

Comme PHP, et contrairement à de nombreux autres langages (Rust, Java, JS, etc.), Golang a besoin de fonctions "helper" pour effectuer la plupart des opérations de type associées. . Nous pouvons les considérer comme des types « anémiques », car ils n’ont pas d’« utilité » qui leur est attachée.

go mod tidy
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Donc, si vous travaillez avec un type "String", vous disposez d'autres packages comme strconv ou des chaînes pour le manipuler ! Mais voici une règle d'or pour ne jamais oublier quel paquet regarder : si votre type est une chaîne, recherchez le même paquet avec un nom pluriel !

En un mot, cela vous donnera des fonctions liées à []Type et Type :

  • Type de chaîne -> import ("strings") pour des opérations telles que : Contains(), Upper(), Split() ...
  • Type d'octets -> importer ("octets") pour des opérations comme Include(), Compare(), Split() ...
  • et ainsi de suite !

Jetez un oeil au code, vous pourrez ainsi valider par vous-même :

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est censé être simple, mais j'ai eu du mal avec ça pendant un moment jusqu'à ce que cela me rentre dans la tête. Peut-être qu'utiliser Laravel et leurs fonctions d'assistance pendant trop d'années m'a fait oublier à quel point il est difficile de coder sans Framework :D

4.2 Forfaits : éléments utiles

Pendant que j'explorais les outils et les projets, j'ai eu une très bonne introduction à de nombreux projets et j'aimerais lister chacun d'eux ainsi que les bibliothèques que j'ai utilisées :

  • Construisez votre propre défi Shell :
    • forfaits :
      • fmt : Bibliothèque d'E/S (numériser/lire et écrire des éléments sur votre écran)
      • os : fonctions et assistants qui communiquent directement avec votre système opérationnel.
      • strconv : convertit des types de données spécifiques en chaîne ou convertit une chaîne en n'importe quel type défini.
  • Créez votre propre défi de serveur (HTTP|DNS) :
    • forfaits :
      • net : couche d'intégration avec les protocoles d'E/S réseau tels que HTTP, TCP, UDP et Unix Domain Sockets
      • [forfaits précédents...]
  • Devoirs de niveau intermédiaire ?
    • forfaits :
      • flag : Capture vos arguments CLI dans des variables
      • log : Ajoute les chaînes de Log à votre application
      • crypto/rand : Générateur aléatoire cryptographique sécurisé
      • math/rand : Générateur aléatoire de nombres mathématiques
      • heure : Durée/Temps Lib

Voici une vue déroulante de toutes les implémentations de packages afin que vous puissiez les consulter. Il existe BEAUCOUP de packages std sympas qui peuvent être cités ici.

ATTENTION : ça fait BEAUCOUP DE CODE ! :p
N'oubliez pas de commenter vos fonctionnalités préférées (outre les goroutines et les chaînes) :p

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Sérieusement, c'est tout simplement incroyable ! Alors, continuons pour les tests maintenant.

5. Les tests dans Go sont SI SIMPLES

Dans mon deuxième projet utilisant Go, j'ai vu une opportunité d'apprendre les tests tout en créant des objets Requêtes et réponses. Dans l'environnement PHP, vous utilisez probablement une bibliothèque tierce comme PHPUnit ou Pest. Droite? Dans l’environnement Go, c’est FACILE ! Tout ce que vous avez à faire est :

  • Créez un fichier à l'intérieur d'un package : Dans person.go vous écrirez les fonctions que vous souhaitez tester ;
  • Créez un fichier de test pour votre package :** créez un fichier appelé person_test.go et commencez à écrire vos propres tests !

Disons que nous avons Requests.go et Requests_test.go dans notre dossier de package, où Requests.go est :

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

5.1 Tests : tests de base

Un test dans Go est considéré comme RÉUSSI (vert) si (t *Testing.T).Errorf() n'est pas appelé dans votre fonction de test. Il suit également le même concept d'encapsulation introduit précédemment :

  • Fonctions de test commençant par majuscules sont identifiées par le Test Runner
  • Les Fonctions de test commençant par les minuscules sont ignorées (généralement des fonctions d'assistance)
mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Vous pouvez créer vos propres fonctions d'assistance pour tester. Assurez-vous simplement de ne pas empiéter sur le domaine du module lors de ces tests !

5.2 Tests : modèle Jetbrains

J'utilise Goland depuis le premier jour, donc la plupart des choses ont été plus faciles pour moi. Ainsi, chaque fois que je démarre un nouveau test, j'obtiens ce passe-partout avec une structure de test Unity qui s'exécute en parallèle (goroutines) par défaut.

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

5.3 Tests : exécution de tests

Ok, maintenant nous savons à quel point il est faciled'écrire des tests dans Go, mais que diriez-vous de les exécuter ? Tâche simple ! Tout ce que vous avez à faire est d'accéder au dossier du package et d'exécuter :

go mod tidy
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Veuillez noter quelques tests pour vos affaires. Ce n'est pas si difficile si on dissocie ce qui est nécessaire :p

6. Méfiez-vous des importations cycliques

Au cours de mes dernières années de développement, j'ai toujours essayé de modulariser tous mes projets d'une manière qui répond à mes besoins, sans rester bloqué sur des trucs "Clean Arch" ou "Domain Driven Design" . Cependant, lors de mes premières tentatives de fractionnement de mes colis, j'ai eu l'erreur "Importation cyclique" et je me suis dit : COMBIEN DE TEMPS N'AI PAS VU QUELQUE CHOSE COMME CELA ?

Pendant mes 2 années en PHP, j'ai eu le même problème avec l'enfer de l'importation, où on ne pouvait pas ne pas importer le même fichier DEUX FOIS dans un flux particulier. C'était avant que je rencontre le PSR-4 (chargement automatique) (qui a changé mes jours PHP pour toujours !!) et maintenant, il y a des années, j'ai du mal avec ça dans Go.

Considérons un scénario d'importations cycliques :

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Lorsque vous essayez de compiler quelque chose qui signale les importations cycliques dans Go, vous recevrez une erreur du type :

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

Copier après la connexion
Copier après la connexion
Copier après la connexion

Et à ce moment-là, vous devez commencer à décomposer vos dépendances/packages afin de l'éviter.

TLDR : n'importez pas le même package dans un endroit qui sera chargé plusieurs fois.

7. Différer ceci, différer cela... Mais qu'est-ce qu'un Différer ?

Je n'ai pas cherché, mais c'était la première fois que je voyais le mot réservé defer dans un langage de programmation. Et comme il ne faisait pas partie des "mots génériques réservés", je l'ai ignoré pendant une semaine entière !

Puis un de mes collègues de travail, Dusan, m'a donné une leçon de gestion de la mémoire en Go après m'avoir vu lutter avec la langue pendant quelques heures. (Oui, c'est un cri :p)

Le problème est que chaque fois que vous ouvrez un tampon/une connexion à quelque chose, vous DEVEZ LE FERMER ! Je me souviens que lorsque je travaillais avec des serveurs MapleStory (Java) en 2014, le problème le plus courant était les fuites de mémoire, simplement parce que les développeurs ne fermaient pas les connexions à la base de données.

C'est OK à OUBLIER ! Mais ce n'est pas OK de passer la révision du code LOL

Voici un exemple en Java :

mkdir go-fodase
cd go-fodase

# go mod init <module-name>
go mod init github.com/danielhe4rt/go-fodase
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Lors du codage de Golang, ils donnent cet attribut defer pour que vous n'oubliez pas de fermer vos fichiers juste après l'avoir ouvert.

Différer signifie « Déférence », qui est un moyen de « Nettoyer » vos ressources une fois l'exécution de cette partie spécifique du code terminée.

# folder: ~/go-fodase
cat go.mod

# module github.com/danielhe4rt/gofodase
# 
# go 1.23.2
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Vous pouvez également avoir de nombreux reports au sein d'une fonction et l'ORDRE DEFER est important ! Si vous différez database2 puis différez database1, les deux processus seront nettoyés dans le même ordre.

go mod tidy
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est un moyen très simple de ne pas foirer empêcher votre projet d'avoir une fuite de mémoire. N'oubliez pas de l'utiliser chaque fois que vous diffusez quelque chose.

8. Gestion des erreurs pour les Noobs

La gestion des erreurs au début sera quelque chose comme : vérifiez si la fonction que vous utilisez renvoie un type d'erreur et validez-la à CHAQUE PUTAIN ​​FOIS ! Voici un exemple de ce dont je parle :

# go run <your-main-file>

# Environment 1
# .
# ├── go.mod
# └── main.go
go run app.go

# Environment 2
# .
# ├── go.mod
# └── src
#     └── main.go
go run src/app.go
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Pour être honnête, je DÉTESTE cette syntaxe. Cependant, cela fait partie du langage et ce sera quelque chose que vous rencontrerez au cours de vos journées de codage.

Les fonctions avec des erreurs peuvent renvoyer une erreur ou (T, erreur), et heureusement Go ne vous laissera pas l'oublier.

package main

import(
    "fmt"
)

func main () {
    fmt.Println("whats up! don't forget to like this article <3")
}

Copier après la connexion
Copier après la connexion
Copier après la connexion

Spamez votre code avec err != nil et tout ira bien, promis ! :D

9. Conclusion : défi de codage à faible latence

Mis à part tout le stress et les heures passées à essayer de comprendre l'environnement, c'était un défi sympa d'apprendre une nouvelle langue avec mes téléspectateurs Twitch. Beaucoup d’entre eux me demandaient depuis longtemps de vérifier et nous y sommes.

Tous ces points reflètent mon expérience de développement personnel avec la langue, et le but était de partager les choses que j'ai vécues pendant ces 2 semaines d'étude de la langue.

Bonus 9.1 : Défi de codage

Récemment, mon coéquipier m'a mis au défi de relever un défi ScyllaDB et cela m'a beaucoup appris sur le parallélisme, les pools et la limitation de débit. C'est le genre de défi auquel de nombreuses entreprises sont confrontées pour rendre leurs produits plus performants !

Le but du défi est de créer une petite application en ligne de commande Go qui insère des données aléatoires dans ScyllaDB tout en limitant le nombre de requêtes.

Vous pouvez trouver le défi du référentiel ici : github.com/basementdevs/throttling-requests-scylla-test. Nous recrutons également ! Vous pouvez retrouver les postes ouverts dans notre section carrières !

Merci d'avoir lu ! J'espère que cet article vous a fourni des informations précieuses sur l'apprentissage du Golang. N'hésitez pas à partager vos réflexions ou expériences.

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!

source:dev.to
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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!