Il n'y a pas beaucoup de code Go pour apprendre le langage, et je suis sûr que je ne suis pas le seul à l'expérimenter. Donc, si vous découvrez quelque chose d'intéressant sur la langue, veuillez poster un exemple ici.
Je recherche aussi
manières idiomatiques de faire les choses dans Go,
Prise en charge ARM telle que 8 bits ou 16 bits. D langue ne le font toujours pas.
1
La bibliothèque ( golang.org/pkg ) est une excellente source pour apprendre comment go est utilisé. Personnellement, je trouve qu'apprendre comment les structures de données sont implémentées est utile pour apprendre la langue.
tkokasih
Réponses:
35
Différer les déclarations
Une instruction "defer" appelle une fonction dont l'exécution est différée au moment où la fonction environnante est renvoyée.
DeferStmt = Expression "différer".
L'expression doit être un appel de fonction ou de méthode. Chaque fois que l'instruction "defer" s'exécute, les paramètres de l'appel de fonction sont évalués et enregistrés à nouveau, mais la fonction n'est pas appelée. Les appels de fonction différés sont exécutés dans l'ordre LIFO juste avant le retour de la fonction environnante, mais après que les valeurs de retour, le cas échéant, ont été évaluées.
lock(l);
defer unlock(l);// unlocking happens before surrounding function returns// prints 3 2 1 0 before surrounding function returnsfor i :=0; i <=3; i++{
defer fmt.Print(i);}
Mettre à jour:
deferest maintenant aussi la manière idiomatique de gérer panicde manière exceptionnelle :
package main
import"fmt"
func main(){
f()
fmt.Println("Returned normally from f.")}
func f(){
defer func(){if r := recover(); r !=nil{
fmt.Println("Recovered in f", r)}}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")}
func g(i int){if i >3{
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i+1)}
@Mike: si vous comparez avec des blocs de "essayez: .. enfin:" LIFO se niche de la même manière. Pour les paires ouverture / fermeture de ressources, etc., une imbrication comme celle-ci est la seule chose qui ait du sens (la première ouverture se fermera en dernier).
u0b34a0f6ae
25
Les fichiers objets Go incluent en fait un en-tête en clair:
jurily@jurily ~/workspace/go/euler31 $ 6g euler31.go
jurily@jurily ~/workspace/go/euler31 $ cat euler31.6
amd64
exports automatically generated from
euler31.go inpackage"main"import
$$ // exportspackage main
var main.coin [9]int
func main.howmany (amount int, max int)(?int)
func main.main ()var main.initdone· uint8
func main.init ()
$$ // local types
type main.dsigddd_1·1struct{?int}
$$
!<binary segment>
Cela ressemble plus à une fonctionnalité cachée qu'à un exemple idiomatique
hasen
22
J'ai vu quelques personnes se plaindre de la boucle for, du genre "pourquoi devrions-nous avoir à dire i = 0; i < len; i++de nos jours?".
Je ne suis pas d'accord, j'aime la construction for. Vous pouvez utiliser la version longue si vous le souhaitez, mais le Go idiomatique est
var a =[]int{1,2,3}for i, v := range a {
fmt.Println(i, v)}
La for .. rangeconstruction boucle sur tous les éléments et fournit deux valeurs: l'index iet la valeur v.
range fonctionne également sur les cartes et les canaux.
Néanmoins, si vous n'aimez pas forsous quelque forme que ce soit, vous pouvez définir each, mapetc. en quelques lignes:
type IntArr[]int// 'each' takes a function argument.// The function must accept two ints, the index and value,// and will be called on each element in turn.
func (a IntArr) each(fn func(index,valueint)){for i, v := range a {
fn(i, v)}}
func main(){var a =IntArr([]int{2,0,0,9})// create int slice and cast to IntArrvar fnPrint = func(i, v int){
fmt.Println(i,":", v)}// create a function
a.each(fnPrint)// call on each element}
Je ne suis pas sûr de ce qui était censé être le problème avec le formatage; Je l'ai restauré.
5
Les auteurs de Go recommandent à gofmtvotre code :-)
ℝaphink
Je ne peux pas le compiler: $ ../go/src/cmd/6g/6g SO.go SO.go: 34: undefined: json.StringToJson
ℝaphink
@Raphink: la langue a changé depuis que j'ai fait ça.
Ouais, savez-vous peut-être quel est l'équivalent le plus proche du StringToJson? Auparavant, il mettait en place un constructeur en interne, maintenant il faut fournir le sien avec une structure native prédéfinie?
type ByteSize float64
const(
_ = iota;// ignore first value by assigning to blank identifier
KB ByteSize=1<<(10*iota)
MB
GB
TB
PB
YB
)// This implicitly repeats to fill in all the values (!)
switch i := x.(type){casenil:
printString("x is nil");caseint:
printInt(i);// i is an intcasefloat:
printFloat(i);// i is a floatcase func(int)float:
printFunction(i);// i is a functioncasebool,string:
printString("type is bool or string");// i is an interface{}default:
printString("don't know the type");}
Les "paramètres" de retour ou de résultat d'une fonction Go peuvent être nommés et utilisés comme variables régulières, tout comme les paramètres entrants. Lorsqu'ils sont nommés, ils sont initialisés aux valeurs nulles pour leurs types lorsque la fonction commence; si la fonction exécute une instruction de retour sans argument, les valeurs actuelles des paramètres de résultat sont utilisées comme valeurs renvoyées.
Les noms ne sont pas obligatoires mais ils peuvent rendre le code plus court et plus clair: ce sont de la documentation. Si nous nommons les résultats de nextInt, il devient évident quel int renvoyé est lequel.
Étant donné que les résultats nommés sont initialisés et liés à un retour sans fioritures, ils peuvent simplifier autant que clarifier. Voici une version de io.ReadFull qui les utilise bien:
L'opérateur de réception lui - même est maintenant une opération de blocage, à partir de Go 1.0.3. La spécification a été modifiée: golang.org/ref/spec#Receive_operator . Veuillez essayer le comportement de blocage (blocage) ici: play.golang.org/p/0yurtWW4Q3
Deleplace
13
/*
* How many different ways can £2 be made using any number of coins?
* Now with 100% less semicolons!
*/package main
import"fmt"/* This line took me over 10 minutes to figure out.
* "[...]" means "figure out the size yourself"
* If you only specify "[]", it will try to create a slice, which is a reference to an existing array.
* Also, ":=" doesn't work here.
*/var coin =[...]int{0,1,2,5,10,20,50,100,200}
func howmany(amount int, max int)int{if amount ==0{return1}if amount <0{return0}if max <=0&& amount >=1{return0}// recursion works as expectedreturn howmany(amount, max-1)+ howmany(amount-coin[max], max)}
func main(){
fmt.Println(howmany(200, len(coin)-1))}
Je suggérerais de supprimer le nom du site de résolution de problèmes ainsi que le numéro d'identification. Peut-être reformulez la question. Pour ne pas gâcher le problème à quelqu'un qui trébuche dessus. Ou en essayant de tricher en recherchant le problème sur le net d'ailleurs.
J'aime que vous puissiez redéfinir des types, y compris des primitives comme int, autant de fois que vous le souhaitez et attacher différentes méthodes. Comme définir un type RomanNumeral:
package main
import("fmt""strings")var numText ="zero one two three four five six seven eight nine ten"var numRoman ="- I II III IV V VI VII IX X"var aText = strings.Split(numText," ")var aRoman = strings.Split(numRoman," ")
type TextNumberint
type RomanNumberint
func (n TextNumber)String()string{return aText[n]}
func (n RomanNumber)String()string{return aRoman[n]}
func main(){var i =5
fmt.Println("Number: ", i,TextNumber(i),RomanNumber(i))}
Qui imprime
Number:5 five V
L' RomanNumber()appel est essentiellement un cast, il redéfinit le type int comme un type plus spécifique d'int. Et des Println()appels String()dans les coulisses.
C'est un vrai idiome qui est assez important: comment introduire des données dans un canal et le fermer par la suite. Avec cela, vous pouvez faire des itérateurs simples (puisque range acceptera un canal) ou des filtres.
// return a channel that doubles the values in the input channel
func DoublingIterator(input chan int) chan int{
outch := make(chan int);// start a goroutine to feed the channel (asynchronously)
go func(){for x := range input {
outch <-2*x;}// close the channel we created and control
close(outch);}();return outch;}
+1. En outre, vous pouvez également faire passer les chaînes à travers les chaînes.
György Andrasek
5
Mais veillez à ne pas sortir d'une boucle for x: = range chan {}, vous fuiriez le goroutine, et toute la mémoire qu'il référence.
Jeff Allen
3
@JeffAllen que diriez-vous defer close(outch);de la première déclaration du goroutine?
1
Defer met en file d'attente une instruction pour exécution lorsque la fonction retourne, quel que soit le point de retour utilisé. Mais si l'entrée de canal n'est jamais fermée, la fonction anonyme de cet exemple ne quittera jamais la boucle for.
Jeff Allen
11
Timeout pour les lectures de canal:
ticker := time.NewTicker(ns);select{case v :=<- chan_target:
do_something_with_v;case<- ticker.C:
handle_timeout;}
Il y a une configuration de make system que vous pouvez utiliser dans $ GOROOT / src
Configurez votre makefile avec
TARG=foobar # Name of package to compile
GOFILES=foo.go bar.go # Go sources
CGOFILES=bang.cgo # Sources to run cgo on
OFILES=a_c_file.$O # Sources compiled with $Oc# $O is the arch number (6 for x86_64)
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
Vous pouvez ensuite utiliser les outils de test automatisés en exécutant make test, ou ajouter le package et les objets partagés de cgo à votre $ GOROOT avec make install.
Il s'agit d'une implémentation d'une pile. Il illustre l'ajout de méthodes à un type.
Je voulais en faire une partie de la pile en une tranche et utiliser les propriétés de la tranche, mais bien que cela fonctionne sans le type, je ne pouvais pas voir la syntaxe pour définir une tranche avec un type.
package main
import"fmt"import"os"const stack_max =100
type Stack2struct{
stack [stack_max]string
size int}
func (s *Stack2) push(pushed_string string){
n := s.size
if n >= stack_max-1{
fmt.Print("Oh noes\n")
os.Exit(1)}
s.size++
s.stack[n]= pushed_string
}
func (s *Stack2) pop()string{
n := s.size
if n ==0{
fmt.Print("Underflow\n")
os.Exit(1)}
top := s.stack[n-1]
s.size--return top
}
func (s *Stack2) print_all(){
n := s.size
fmt.Printf("Stack size is %d\n", n)for i :=0; i < n; i++{
fmt.Printf("%d:\t%s\n", i, s.stack[i])}}
func main(){
stack :=new(Stack2)
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()}
Plutôt que d'utiliser fmt.Printf(...); os.Exit();, vous pouvez utiliser panic(...).
notnoop
1
Cela donne une trace de pile, ce que je ne veux pas.
3
Pourquoi est-ce limité? Go est un langage géré et gc. Votre pile peut être aussi profonde que vous le souhaitez. Utilisez le nouveau intégré append (), qui fera quelque chose comme la réallocation de C quand il en aura besoin.
Jeff Allen
"Go n'a pas besoin de génériques", ont-ils dit.
cubuspl42
4
Appeler le code C depuis Go
Il est possible d'accéder au niveau inférieur de go en utilisant le runtime c.
Les fonctions C sont sous la forme
voidpackage·function(...)
(notez que le séparateur de points est un caractère unicode) où les arguments peuvent être des types go de base, des tranches, des chaînes, etc. Pour renvoyer un appel de valeur
FLUSH(&ret)
(vous pouvez renvoyer plus d'une valeur)
Par exemple, pour créer une fonction
package foo
bar( a int32, b string)(c float32 ){
c =1.3+ float32(a - int32(len(b))}
en C vous utilisez
#include"runtime.h"void foo·bar(int32 a,String b, float32 c){
c =1.3+ a - b.len;
FLUSH(&c);}
Notez que vous devez toujours déclarer la fonction dans un fichier go, et que vous devrez vous occuper de la mémoire vous-même. Je ne sais pas s'il est possible d'appeler des bibliothèques externes en utilisant cela, il peut être préférable d'utiliser cgo.
Regardez $ GOROOT / src / pkg / runtime pour des exemples utilisés dans le runtime.
Voir aussi cette réponse pour lier du code C ++ avec go.
Utilise-t-il vraiment le «point volant»? Je n'ose pas éditer, mais cela semble un peu inattendu et radical.
détendre
Oui, vous devez compiler avec 6c (ou 8c, etc.). Je ne pense pas que gcc gère les identifiants Unicode.
Scott Wales
1
Je pense que la période AltGr + est la même · mais avec unicode, je ne suis pas sûr. J'ai été très surpris de voir que dans la source j'ai lu .. pourquoi ne pas utiliser quelque chose comme ::?
u0b34a0f6ae
Le caractère est MIDDLE DOT U + 00B7. L'analyseur a peut-être été truqué pour qu'il le voit comme un caractère afin de créer un identificateur c valide, ce qui, je crois, empêcherait ::.
Scott Wales
4
Le '·' est juste un hack temporaire, Rob était même surpris qu'il soit toujours là, il a dit qu'il allait être remplacé par quelque chose de moins idiosyncratique.
uriel
4
Voici un exemple d'utilisation du package sqlite3.
Oui je l'ai fait. Cela se résume à "Il y a beaucoup plus là-dedans, passons au sujet suivant".
György Andrasek
Oui, apparemment beaucoup à dire avec peu de temps
3
Une pile basée sur l'autre réponse, mais utilisant l'ajout de tranche pour ne pas avoir de limite de taille.
package main
import"fmt"import"os"
type Stack2struct{// initial storage space for the stack
stack [10]string
cur []string}
func (s *Stack2) push(pushed_string string){
s.cur = append(s.cur, pushed_string)}
func (s *Stack2) pop()(popped string){if len(s.cur)==0{
fmt.Print("Underflow\n")
os.Exit(1)}
popped = s.cur[len(s.cur)-1]
s.cur = s.cur[0: len(s.cur)-1]return}
func (s *Stack2) print_all(){
fmt.Printf("Stack size is %d\n", len(s.cur))for i, s := range s.cur {
fmt.Printf("%d:\t%s\n", i, s)}}
func NewStack()(stack *Stack2){
stack =new(Stack2)// init the slice to an empty slice of the underlying storage
stack.cur = stack.stack[0:0]return}
func main(){
stack :=NewStack()
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()}
Bien sûr. C'est exactement ce qui se passe ici. J'aime juste le forevermot - clé. Même Qt a une macro pour cela.
György Andrasek
6
mais Go n'a pas besoin d'une macro ou d'un joli alias de true pour ce faire.
u0b34a0f6ae
@ kaizer.se: Le point de Jurily est que for ever(après avoir déclaré la variable) est quelque chose de mignon que vous pouvez faire dans Go si vous le souhaitez. Il ressemble à l'anglais (modulo le blanc).
Frank
8
c'est quelque chose de mignon que vous pouvez faire en C aussi .. :-)#define ever (;;)
u0b34a0f6ae
2
Il y a beaucoup de petits programmes testdans le répertoire principal. Exemples:
peano.go imprime les factorielles.
hilbert.go a une certaine multiplication matricielle.
Réponses:
Différer les déclarations
Mettre à jour:
defer
est maintenant aussi la manière idiomatique de gérerpanic
de manière exceptionnelle :la source
Les fichiers objets Go incluent en fait un en-tête en clair:
la source
J'ai vu quelques personnes se plaindre de la boucle for, du genre "pourquoi devrions-nous avoir à dire
i = 0; i < len; i++
de nos jours?".Je ne suis pas d'accord, j'aime la construction for. Vous pouvez utiliser la version longue si vous le souhaitez, mais le Go idiomatique est
La
for .. range
construction boucle sur tous les éléments et fournit deux valeurs: l'indexi
et la valeurv
.range
fonctionne également sur les cartes et les canaux.Néanmoins, si vous n'aimez pas
for
sous quelque forme que ce soit, vous pouvez définireach
,map
etc. en quelques lignes:impressions
Je commence à aimer beaucoup Go :)
la source
range
ne soit bien que s'il est compilé avec le même code que la boucle for-3.Allez chercher votre réputation de stackoverflow
Ceci est une traduction de cette réponse .
Merci à Scott Wales pour son aide avec .Read ().
Cela semble encore assez maladroit, avec les deux chaînes et deux tampons, donc si des experts de Go ont des conseils, faites le moi savoir.
la source
gofmt
votre code :-)Voici un bel exemple d'iota du post de Kinopiko :
la source
Vous pouvez permuter les variables par affectation parallèle:
simple mais efficace.
la source
Voici un idiome de la page Effective Go
L'instruction switch passe à true lorsqu'aucune expression n'est donnée. Donc c'est équivalent à
Pour le moment, la version Switch me semble un peu plus propre.
la source
Switch True
…)Commutateurs de type :
la source
Lors de l'importation de packages, vous pouvez redéfinir le nom comme vous le souhaitez:
la source
Paramètres de résultat nommés
la source
D'après la réponse de James Antill :
Aussi, un écueil potentiel: la différence subtile entre les opérateurs de réception et d'envoi:
la source
la source
J'aime que vous puissiez redéfinir des types, y compris des primitives comme int, autant de fois que vous le souhaitez et attacher différentes méthodes. Comme définir un type RomanNumeral:
Qui imprime
L'
RomanNumber()
appel est essentiellement un cast, il redéfinit le type int comme un type plus spécifique d'int. Et desPrintln()
appelsString()
dans les coulisses.la source
Retourner une chaîne
C'est un vrai idiome qui est assez important: comment introduire des données dans un canal et le fermer par la suite. Avec cela, vous pouvez faire des itérateurs simples (puisque range acceptera un canal) ou des filtres.
la source
defer close(outch);
de la première déclaration du goroutine?Timeout pour les lectures de canal:
Volé à Davies Liu .
la source
Puisque range vérifie automatiquement un canal fermé, nous pouvons raccourcir ceci:
la source
Il y a une configuration de make system que vous pouvez utiliser dans $ GOROOT / src
Configurez votre makefile avec
Vous pouvez ensuite utiliser les outils de test automatisés en exécutant make test, ou ajouter le package et les objets partagés de cgo à votre $ GOROOT avec make install.
la source
Une autre chose intéressante dans Go est que
godoc
. Vous pouvez l'exécuter en tant que serveur Web sur votre ordinateur en utilisantoù 8080 est le numéro de port, et le site Web entier à golang.org est alors disponible à
localhost:8080
.la source
Il s'agit d'une implémentation d'une pile. Il illustre l'ajout de méthodes à un type.
Je voulais en faire une partie de la pile en une tranche et utiliser les propriétés de la tranche, mais bien que cela fonctionne sans le
type
, je ne pouvais pas voir la syntaxe pour définir une tranche avec untype
.la source
fmt.Printf(...); os.Exit();
, vous pouvez utiliserpanic(...)
.Appeler le code C depuis Go
Il est possible d'accéder au niveau inférieur de go en utilisant le runtime c.
Les fonctions C sont sous la forme
(notez que le séparateur de points est un caractère unicode) où les arguments peuvent être des types go de base, des tranches, des chaînes, etc. Pour renvoyer un appel de valeur
(vous pouvez renvoyer plus d'une valeur)
Par exemple, pour créer une fonction
en C vous utilisez
Notez que vous devez toujours déclarer la fonction dans un fichier go, et que vous devrez vous occuper de la mémoire vous-même. Je ne sais pas s'il est possible d'appeler des bibliothèques externes en utilisant cela, il peut être préférable d'utiliser cgo.
Regardez $ GOROOT / src / pkg / runtime pour des exemples utilisés dans le runtime.
Voir aussi cette réponse pour lier du code C ++ avec go.
la source
Voici un exemple d'utilisation du package sqlite3.
http://github.com/bikal/gosqlite-example
la source
Avez-vous regardé cette conférence ? Il montre beaucoup de trucs sympas que vous pouvez faire (fin de la conférence)
la source
Une pile basée sur l'autre réponse, mais utilisant l'ajout de tranche pour ne pas avoir de limite de taille.
la source
la source
for { /* infinite loop */ }
est assez.forever
mot - clé. Même Qt a une macro pour cela.for ever
(après avoir déclaré la variable) est quelque chose de mignon que vous pouvez faire dans Go si vous le souhaitez. Il ressemble à l'anglais (modulo le blanc).#define ever (;;)
Il y a beaucoup de petits programmes
test
dans le répertoire principal. Exemples:peano.go
imprime les factorielles.hilbert.go
a une certaine multiplication matricielle.iota.go
a des exemples de la chose bizarre iota.la source