2009-11-14 23 views
38

Quindi, il grande ronzio degli ultimi giorni è Go, la nuova lingua di Google. Supponendo che tu sia un appassionato di linguaggi di programmazione ossessivo come me, l'hai scaricato, costruito e lanciato il tuo programma "Hello, 世界" (non è bello usare un linguaggio scritto dagli inventori di UTF-8?) . Hai letto tutti the tutorial, Effective Go e alcuni degli altri documenti.Cosa puoi fare in 30 righe di Go? Puoi creare un programma utile e completo che dimostri le sue funzionalità?

Ora, che cosa hai intenzione di fare con esso?

Mi piacerebbe vedere alcuni demo che mostrano il potere di Go. Cosa puoi fare in un breve programma? Mostra il tuo codice di esempio migliore. Anche se la vera misura di una lingua non può essere presa fino a quando non hai scritto e mantenuto una grande base di codice con un team di molti programmatori nel corso di un progetto con requisiti in evoluzione, vedendo quanto puoi fare in un numero limitato di il codice aiuta a dimostrare il potere espressivo di una lingua. Mi piacerebbe vedere programmi brevi e completi che esercitino veramente le nuove caratteristiche uniche di Go; non solo snippet o "Hello, World".

Quindi, pubblica un bel codice che hai scritto con Go. Approfitta delle sue caratteristiche uniche, come le sue goroutine e canali per la concorrenza, o il suo sistema di tipi basato sull'interfaccia. Puoi scrivere un server di chat primitivo o un fantastico IRC bot? Implementare un set Mandelbrot parallelo che riduca a molti core? Scrivi un interprete per un piccolo linguaggio? E puoi fare tutto in 30 righe?

Ho scelto 30 arbitrariamente quanto circa quello che puoi inserire in un blocco di codice Stack Overflow senza farlo traboccare e ottenere una barra di scorrimento; dovrebbe essere abbastanza per fare qualcosa di interessante senza golf troppo, ma abbastanza breve da mantenere l'attenzione di tutti per una rapida demo. Ad esempio, con un po 'di riformattazione, l'esempio web server dovrebbe essere in grado di adattarsi (senza contare i dati).

Mostraci il tuo codice Go!

+10

Ehi, perché i downvotes e gli stretti voti? Facciamo codice golf qui, e facciamo alcune domande a risposta aperta sui punti di forza o di debolezza delle varie tecnologie, purché non siano troppo controversi o soggetti; perché non alcuni demo di ciò che una nuova lingua è buono per? Se pensi che questo dovrebbe essere il wiki della comunità, dillo e potrei farlo, ma non credo che questa domanda debba essere chiusa. –

+1

s/subject/soggettivo/ –

+4

Le domande sul golf in codice hanno un obiettivo specifico in mente. Questa domanda, tuttavia, sembra troppo aperta. Chiedere alle persone di fare * qualsiasi cosa * con una lingua è semplicemente troppo vago. – gnovice

risposta

8

Ciò fa un PNG (su stdout) di un orologio che mostra il ora attuale. È appena giocato a golf per adattarsi a trenta linee, quindi il codice non è così pulito come dovrebbe essere.

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

gestire l'IT come

 
8.out > clock.png 

Avviso tutti coloro float64 getta? Non ho mai visto una lingua tanto severa quanto i tipi.


Questo è lo stesso codice fisso con go fix (e qualche modifica manuale) e quindi formattato automaticamente utilizzando go fmt. Alcune newline dove sono state inserite manualmente.

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

"Non ho mai visto una lingua così severa come Go sui tipi." OCaml utilizza +. invece di + per il doppio. –

+0

'gofmt' sarebbe davvero bello :). – crazy2be

+0

Correggere il codice: './clock.go:5: undefined: image.RGBAColor ./clock.go:21: impossibile utilizzare clock_size (tipo int) come tipo image.Rectangle nell'argomento di funzione ./clock.go : 21: troppi argomenti nella chiamata a image.NewRGBA ./clock.go:24: undefined: time.LocalTime' – Flavius

4

OK, farò rotolare la palla. Ecco il mio primo programma Go. È un server di chat molto primitivo e si adatta a 30 righe di 80 caratteri se lo comprime un po '; formattato con gofmt, è 60 linee. Ascolta una porta hard coded (4242), praticamente non gestisce gli errori e non gestisce la disconnessione dei client se non interrompendo il tentativo di leggere da un client se riceve un errore.

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

Compilare ed eseguire con:

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

E poi in un paio di altri terminali, in contatto con

$ nc localhost 4242 
+0

Adoro questo esempio, ma non riesco a capire come funziona questo specifico bit: c. (Client).ricevi Pensavo che la convention fosse client (c) .receive Ti spiace spiegare? –

+0

Sicuro. Questa è un'asserzione di tipo (http://golang.org/doc/go_spec.html#Type_assertions); asserisce che il tipo è ciò che si specifica (o si conforma all'interfaccia che si specifica) e consente di chiamare i metodi definiti su quel tipo o interfaccia. La sintassi che menzioni è una conversione (http://golang.org/doc/go_spec.html#Conversions), che converte tra tipi compatibili (come i tipi di interi). Credo che le conversioni funzionino solo per i tipi buit-in (numeri e stringhe). –

+0

Ah, capisco. Non ero arrivato fino alle dichiarazioni di tipo nelle specifiche. Grazie. –

0

Ho copiato questo da qualche parte. Abbastanza semplice, ma mostra alcune caratteristiche.

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

Prova ad attribuire qualsiasi codice che hai copiato da altrove alla sua fonte originale. Inoltre, aiuta a descrivere cosa dovrebbe fare il codice e a formattare il codice per renderlo leggibile. Ho modificato la tua risposta per formattare il codice per te; se rientri ogni riga con 4 spazi (o seleziona il testo e premi il pulsante '{}') Stack Overflow lo mostrerà come codice con tutti i rientri preservati. –

+0

Questo non viene compilato bene da parte mia. Dice: "troppi argomenti in chiamata a os.Open. Significa che l'API è stata modificata? –

+1

Se non si compila e si sospetta una modifica dell'API, provare a eseguire la correzione su di esso. – Kissaki

4

Mi piace molto i canali di GO e la dichiarazione select, quindi ecco una cosa che dimostra quanto sia facile per esprimere il concetto "andare a prendere il maggior numero di cose possibili entro un certo tempo".

Questo genera quanti più numeri casuali possibili entro 300 millisecondi e restituisce il più grande generato in quel momento.

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() 'è quasi identico a 'time.After()' –

+0

Inoltre, dato che 'select' seleziona a caso un canale se entrambi sono disponibili, potresti tirare i numeri dopo che è scaduto il timeout. Se ti interessa la strana coppia di numeri lì, potrebbe voler fare una seconda lettura non bloccante dal timeout nel caso dei numeri. –

12

Questo è un proxy web che ho scritto per fornire l'accesso non autenticato a un servizio Web che ha richiesto autenticazione base di HTTP. Ne avevo bisogno per un oggetto interno (e ancora lo uso):

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