2009-11-14 8 views
38

Donc, le gros buzz de ces derniers jours est Go, la nouvelle langue de Google. En supposant que vous êtes tous des geeks de langage de programmation obsessionnels comme moi, vous avez tous téléchargé, construit, et exécutez votre programme "Bonjour, 世界" (n'est-ce pas agréable d'utiliser un langage écrit par les inventeurs de UTF-8?) . Vous avez tous lu the tutorial, Effective Go et d'autres documents.Que pouvez-vous faire dans 30 lignes de Go? Pouvez-vous créer un programme utile et complet qui démontre ses caractéristiques?

Maintenant, qu'allez-vous en faire?

Je voudrais voir quelques démos qui montrent la puissance de Go. Que pouvez-vous faire dans un programme bref? Montrez votre meilleur exemple de code. Alors que la vraie mesure d'un langage ne peut pas vraiment être prise tant que vous n'avez pas écrit et maintenu une grande base de code avec une équipe de nombreux programmeurs au cours d'un projet avec des exigences changeantes, voir combien vous pouvez faire dans une quantité limitée de Le code aide à démontrer le pouvoir expressif d'un langage. J'aimerais voir des programmes courts et complets qui exercent vraiment les nouvelles fonctionnalités uniques de Go; pas seulement des extraits ou "Hello, World". Alors, postez du code sympa que vous avez écrit avec Go. Tirez parti de ses caractéristiques uniques, comme ses goroutines et ses canaux de concurrence, ou son système de type basé sur l'interface. Pouvez-vous écrire un serveur de discussion primitif ou un robot IRC sympa? Implémenter un ensemble Mandelbrot parallèle qui s'adapte à plusieurs cœurs? Ecrire un interprète pour une langue minuscule? Et pouvez-vous faire tout cela en 30 lignes? J'ai choisi 30 arbitrairement autant que vous pouvez entrer dans un bloc de code Stack Overflow sans débordement et obtenir une barre de défilement; ça devrait suffire à faire quelque chose d'intéressant sans trop jouer au golf, mais assez court pour garder l'attention de tout le monde pour une démonstration rapide. Par exemple, avec juste un peu de reformatage, l'exemple web server devrait pouvoir s'adapter (sans compter les données).

Montrez-nous votre code Go!

+10

Hey, pourquoi les sous-cotes et votes serrés? Nous codons le golf ici, et nous posons des questions ouvertes sur les forces et les faiblesses des diverses technologies, à condition qu'elles ne soient pas trop controversées ou sujettes à controverse. pourquoi pas des démonstrations de ce à quoi une nouvelle langue est bonne? Si vous pensez que cela devrait être wiki de la communauté, dites-le et je pourrais le faire, mais je ne pense pas que cette question devrait être close. –

+1

s/subject/subjective/ –

+4

Les questions relatives au golf de code ont un objectif spécifique en tête. Cette question, cependant, semble juste trop ouverte. Demander aux gens de faire * n'importe quoi * avec une langue est tout simplement trop vague. – gnovice

Répondre

8

Cela fait un PNG (sur la sortie standard) d'une horloge indiquant la heure actuelle. Il est à peine golfé pour contenir une trentaine de lignes, donc le code n'est pas aussi propre qu'il devrait l'être.

package main 
import ("image"; "image/png"; "math"; "bufio"; "os"; "time") 
const clock_size = 200; 
const radius = clock_size/3; 
var colour image.RGBAColor; 
func circle (clock *image.RGBA) { 
    for angle := float64(0); angle < 360; angle++ { 
     radian_angle := math.Pi * 2 * angle/360; 
     x := radius * math.Sin (radian_angle) + clock_size/2; 
     y := radius * math.Cos (radian_angle) + clock_size/2; 
     clock.Set (int (x), int (y), colour);}} 
func hand (clock *image.RGBA, angle float64, length float64) { 
    radian_angle := math.Pi * 2 * angle; 
    x_inc := math.Sin (radian_angle); 
    y_inc := -math.Cos (radian_angle); 
    for i := float64(0); i < length; i++ { 
     x := i * x_inc + clock_size/2; 
     y := i * y_inc + clock_size/2; 
     clock.Set (int (x), int (y), colour);}} 
func main() { 
    clock := image.NewRGBA (clock_size, clock_size); 
    colour.A = 255; 
    circle (clock); 
    time := time.LocalTime(); 
    hand (clock, (float64(time.Hour) + float64(time.Minute)/60)/12, radius*0.6); // hour hand 
    hand (clock, (float64(time.Minute) + float64(time.Second)/60)/60, radius*0.8); // minute hand 
    out := bufio.NewWriter(os.Stdout); 
    defer out.Flush(); 
    png.Encode(out, clock); 
} 

Exécuter comme

 
8.out > clock.png 

Avis tous ceux float64 jette? Je n'ai jamais vu une langue aussi stricte que Go sur les types.


Ceci est le même code fixe avec go fix (et des modifications manuelles), puis mis en forme automatiquement à l'aide go fmt. Certaines nouvelles lignes ont été insérées manuellement.

package main 

import (
    "bufio" 
    "image" 
    "image/color" 
    "image/png" 
    "math" 
    "os" 
    "time" 
) 

const clock_size = 200 
const radius = clock_size/3 

var colour color.RGBA 

func circle(clock *image.RGBA) { 
    for angle := float64(0); angle < 360; angle++ { 
     radian_angle := math.Pi * 2 * angle/360 
     x := radius*math.Sin(radian_angle) + clock_size/2 
     y := radius*math.Cos(radian_angle) + clock_size/2 
     clock.Set(int(x), int(y), colour) 
    } 
} 

func hand(clock *image.RGBA, angle float64, length float64) { 
    radian_angle := math.Pi * 2 * angle 
    x_inc := math.Sin(radian_angle) 
    y_inc := -math.Cos(radian_angle) 
    for i := float64(0); i < length; i++ { 
     x := i*x_inc + clock_size/2 
     y := i*y_inc + clock_size/2 
     clock.Set(int(x), int(y), colour) 
    } 
} 

func main() { 
    clock := image.NewRGBA(image.Rect(0, 0, clock_size, clock_size)) 
    colour.A = 255 
    circle(clock) 
    time := time.Now() 
    hand(clock, (float64(time.Hour())+float64(time.Minute())/60)/12, radius*0.6) // hour hand 
    hand(clock, (float64(time.Minute())+float64(time.Second())/60)/60, radius*0.8) // minute hand 
    out := bufio.NewWriter(os.Stdout) 
    defer out.Flush() 
    png.Encode(out, clock) 
} 
+7

"Je n'ai jamais vu une langue aussi stricte que les types de Go." OCaml utilise +. au lieu de + pour double. –

+0

'gofmt' serait vraiment sympa :). – crazy2be

+0

Veuillez corriger le code: './clock.go:5: undefined: image.RGBAColor ./clock.go:21: impossible d'utiliser clock_size (type int) comme type image.Rectangle dans l'argument de fonction ./clock.go Trop d'arguments dans l'appel à l'image.NewRGBA ./clock.go:24: undefined: time.LocalTime' – Flavius

4

OK, je vais lancer le bal. Voici mon premier programme Go. C'est un serveur de discussion très primitif, et il peut contenir 30 lignes de 80 caractères si je le compresse un peu; formaté avec gofmt, il est de 60 lignes. Il écoute sur un port codé en dur (4242), n'effectue pratiquement aucune gestion des erreurs et ne gère pas la déconnexion du client autre que l'arrêt de la tentative de lecture d'un client en cas d'erreur.

package main 
import ("net";"container/vector";"bufio";"strings") 
type client struct { conn net.Conn; send chan string; receive chan string } 
func main() { 
    if listener, err := net.Listen("tcp", "0.0.0.0:4242"); err == nil { 
     master := make(chan string, 100); 
     clients := vector.New(0); 
     go runServer(master, clients); 
     for { 
      if conn, err := listener.Accept(); err == nil { 
       c := client{ conn, master, make(chan string, 100) }; 
       clients.Push(c); 
       go runClient(c); 
      } else { break } } } } 
func runServer(master chan string, clients *vector.Vector) { 
    for { 
     message := <-master; 
     clients.Do(func (c interface{}) { c.(client).receive <- message }); } } 
func runClient(c client) { 
    input := make(chan string, 10); 
    go readLines(c, input); 
    for { 
     select { 
     case inMessage := <-input: c.send <- inMessage; 
     case outMessage := <-c.receive: c.conn.Write(strings.Bytes(outMessage)); 
     } } } 
func readLines(c client, input chan string) { 
    reader := bufio.NewReader(c.conn); 
    for { if line, err := reader.ReadString('\n'); err == nil 
      { input <- line; } else { break } } } 

Construire et exécuter avec:

$ 6g server.go 
$ 6l -o server server.6 
$ ./server 

Et puis dans quelques autres terminaux, se connecter avec

$ nc localhost 4242 
+0

J'aime cet exemple, mais je n'arrive pas à comprendre comment fonctionne ce bit spécifique: c. (Client).recevoir Je pensais que la convention était client (c) .recevoir Ça vous dérange d'expliquer? –

+0

Bien sûr. C'est une assertion de type (http://golang.org/doc/go_spec.html#Type_assertions); il affirme que le type est ce que vous spécifiez (ou est conforme à l'interface que vous spécifiez), et vous permet d'appeler des méthodes qui sont définies sur ce type ou cette interface. La syntaxe que vous mentionnez est une conversion (http://golang.org/doc/go_spec.html#Conversions), qui convertit entre les types compatibles (tels que les types entiers). Je crois que les conversions ne fonctionnent que pour les types buit-in (nombres et chaînes). –

+0

Ah, je vois. Je n'avais pas été aussi loin que les affirmations de type dans la spécification. Merci. –

0

Je l'ai copié quelque part. Assez simple, mais montre quelques fonctionnalités.

package main 
import ("fmt"; "os" ;"bufio";"io") 
func main() { 
     if len(os.Args) < 2 { 
       fmt.Printf("usage: catfile \n") 
     } else if pFile, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0); err != nil { 
       fmt.Printf("error opening file : %s\n", err) 
     } else { 
      defer pFile.Close() 
     displayFile(pFile) 
    } 
} 

func displayFile(pFile *os.File) { 
     oReader := bufio.NewReader(pFile); 
     for { 
       if sLine, err := oReader.ReadString('\n'); err == nil { 
      fmt.Printf("%s", sLine) 
     } else { 
      if err != io.EOF {fmt.Printf("error reading file : %s\n", err)} 
        break 
     } 
     } 
} 
+6

Veuillez essayer d'attribuer tout code copié d'ailleurs à sa source d'origine. En outre, il est utile de décrire ce que le code est censé faire et de formater le code pour le rendre lisible. J'ai modifié votre réponse pour mettre en forme le code pour vous; Si vous indentez chaque ligne avec 4 espaces (ou sélectionnez le texte et appuyez sur le bouton {}}, Stack Overflow l'affichera comme du code avec toutes les indentations conservées. –

+0

Cela ne compile pas bien de mon côté. Il dit: "trop ​​d'arguments dans l'appel à os.Open.Est-ce que cela signifie que l'API a changé? –

+1

Si elle ne compile pas et vous soupçonnez une API de changer, essayez' Go Fix 'sur le – Kissaki

4

Je aime vraiment les canaux de go et la déclaration select, alors voici quelque chose qui montre combien il est facile d'exprimer le concept d ' « aller et obtenir autant de choses que possible dans un certain temps ».

Ceci génère autant de nombres aléatoires que possible en 300 millisecondes et renvoie le plus grand nombre généré au cours de cette période.

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func main() { 
    timeout := time.After(300 * time.Millisecond) 
    numbers := make(chan int) // This channel will be used 
    var numberCount int = 0 
    var maxNumber int = 0 

    // Start putting random numbers on the numbers channel 
    go func() { 
    for { 
     numbers <- rand.Int() 
    } 
    }() 

    for { 
    select { 
    case <- timeout: 
     fmt.Printf("%v numbers generated. Max number found: %v.\n", numberCount, maxNumber) 
     return 

    case number := <- numbers: 
     numberCount++ 
     if number > maxNumber { 
     maxNumber = number 
     } 
    } 
    } 
} 
+1

'setTimeout()' est presque identique à 'time.After()' –

+0

En outre, puisque 'select' sélectionne aléatoirement un canal si les deux sont disponibles, vous pouvez tirer des numéros après que le timeout se soit écoulé.Si vous vous souciez de l'étrange couple de chiffres là, vous pourrait vouloir faire une deuxième lecture non bloquante du timeout dans le cas des nombres. –

12

Ceci est un proxy Web que j'ai écrit pour fournir un accès non authentifié à un service Web nécessitant l'authentification de base HTTP. J'en avais besoin pour un truc interne (et je l'utilise toujours):

package main 

import (
    "flag" 
    "log" 
    "net/http" 
    "net/url" 
) 

var target = flag.String("target", "http://www.google.com/", "Where to go.") 
var addr = flag.String("listen", ":12345", "Address/port on which to listen.") 
var auth = flag.String("auth", "", "Authorization header to add (optional).") 

func main() { 
    flag.Parse() 

    targetUrl, uerr := url.Parse(*target) 
    if uerr != nil { 
     log.Fatalf("Error parsing target ``%s'': ", target, uerr.String()) 
    } 

    proxy := http.ReverseProxy{Director: func(req *http.Request) { 
     req.URL.Scheme = targetUrl.Scheme 
     req.URL.Host = targetUrl.Host 
     req.Host = targetUrl.Host 
     if *auth != "" { 
      req.Header.Set("Authorization", *auth) 
     } 
    }} 

    log.Fatal(http.ListenAndServe(*addr, &proxy)) 
}