¿Qué puedes hacer en 30 líneas de Go? ¿Puedes crear un programa útil y completo que demuestre sus características? [cerrado]


Entonces, el gran revuelo en los últimos días es Go, el nuevo lenguaje de Google. Suponiendo que todos son geeks obsesivos del lenguaje de programación como yo, todos lo han descargado, construido y ejecutado su programa "Hola, Hello" (¿no es agradable usar un lenguaje escrito por los inventores de UTF-8?). Todos habéis leído el tutorial, Effective Go , y algunos de los otros documentos.

Ahora, ¿qué vas a hacer con él?

Me gustaría ver algunas demos que muestran el el poder del Go. ¿Qué puedes hacer en un programa breve? Muestra tu mejor código de ejemplo. Si bien la verdadera medida de un lenguaje no se puede tomar realmente hasta que haya escrito y mantenido una base de código grande con un equipo de muchos programadores a lo largo de un proyecto con requisitos cambiantes, ver cuánto puede hacer en una cantidad limitada de código ayuda a demostrar el poder expresivo de un lenguaje. Me gustaría ver programas cortos y completos que realmente ejerciten las nuevas características únicas de Go; no solo fragmentos o "Hola, Mundo".

Así que, publica un código genial que hayas escrito con Go. Aproveche sus características únicas, como sus goroutines y canales para la concurrencia, o su sistema de tipos basado en interfaz. ¿Puedes escribir un servidor de chat primitivo, o un genial bot IRC? Implementar un conjunto paralelo Mandelbrot que escala a muchos núcleos? ¿Escribir un intérprete para un idioma pequeño? ¿Y puedes hacerlo todo en 30 líneas?

Elegí 30 arbitrariamente tanto como puedas caber en una pila Bloque de código de desbordamiento sin que se desborde y obtenga una barra de desplazamiento; debería ser suficiente para hacer algo interesante sin jugar al golf demasiado, pero lo suficientemente corto como para mantener la atención de todos para una demostración rápida. Por ejemplo, con solo un poco de reformateo, el servidor web de ejemplo debería ser capaz de encajar (sin contar los datos).

¡Muéstranos tu código Go!

 38
Author: Brian Campbell, 2009-11-14

5 answers

Esto hace un PNG (en stdout) de una esfera de reloj que muestra la hora actual. Es apenas golfed para caber treinta líneas, por lo que el código no es tan limpio como debería ser.

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

Ejecutarlo como

8.out > clock.png

¿Te das cuenta de todos esos moldes de float64? NUNCA he visto un lenguaje tan estricto como Go about types.


Este es el mismo código arreglado con go fix (y algunos ajustes manuales) y luego formateado automáticamente usando go fmt. Algunas líneas nuevas se insertaron 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)
}
 8
Author: 4 revs, 2 users 62%user181548,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-27 21:58:22

Este es un proxy web que escribí para proporcionar acceso no autenticado a un servicio web que requería autenticación básica HTTP. Lo necesitaba para una cosa interna (y todavía 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))
}
 12
Author: Dustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-23 19:43:59

OK, voy a poner la bola en marcha. Este es mi primer programa. Es un servidor de chat muy primitivo, y cabe en 30 líneas de 80 caracteres si lo comprimo un poco; formateado con gofmt, son 60 líneas. Escucha en un puerto codificado (4242), básicamente no maneja errores, y no maneja la desconexión del cliente aparte de detener el intento de leer de un cliente si recibe un error.

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

Compilar y ejecutar con:

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

Y luego en algunos otros terminales, conectar con

$ nc localhost 4242 
 4
Author: Brian Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-16 01:37:44

Realmente me gustan los canales de go y la declaración select, así que aquí hay algo que muestra lo fácil que es expresar el concepto de "ve y consigue tantas cosas como sea posible dentro de un cierto tiempo".

Esto genera tantos números aleatorios como sea posible dentro de 300 milisegundos y devuelve el mayor generado en ese tiempo.

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
      }
    }
  }
}
 4
Author: jgeewax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-25 15:23:35

Copié esto de alguna parte. Bastante simple, pero muestra algunas características.

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
        } 
        }
}
 0
Author: brianoh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-02 01:42:34