programacion - ¿Qué puedes hacer en 30 líneas de Go? ¿Puedes crear un programa útil y completo que demuestre sus características?
manual de programacion android pdf (5)
Entonces, el gran revuelo en los últimos días es Go , el nuevo lenguaje de Google. Asumiendo que todos ustedes son geeks obsesivos del lenguaje de programación como yo, todos lo han descargado, construido y ejecutado su programa "Hello, 世界" (¿no es agradable usar un lenguaje escrito por los inventores de UTF-8?) . Todos han leído el tutorial , Effective Go y algunos de los otros documentos.
Ahora, ¿qué vas a hacer con eso?
Me gustaría ver algunas demos que muestren el poder de Go. ¿Qué puedes hacer en un breve programa? Muestra tu mejor código de ejemplo. Aunque la verdadera medida de un idioma no se puede tomar hasta que haya escrito y mantenido una gran base de código con un equipo de muchos programadores en el transcurso de un proyecto con requisitos cambiantes, viendo cuánto puede hacer en una cantidad limitada de El código ayuda a demostrar el poder expresivo de un idioma. Me gustaría ver programas cortos y completos que realmente ejerzan las nuevas características únicas de Go; no solo fragmentos o "Hello, World".
Entonces, publica un código genial que hayas escrito con Go. Aproveche sus características únicas, como sus rutinas y canales para concurrencia, o su sistema de tipo basado en interfaz. ¿Puedes escribir un servidor de chat primitivo o un genial bot de IRC? ¿Implementar un conjunto paralelo de Mandelbrot que se adapta a muchos núcleos? ¿Escribir un intérprete para un lenguaje pequeño? ¿Y puedes hacerlo todo en 30 líneas?
Elegí 30 arbitrariamente tanto como pueda en un bloque de código Stack Overflow sin que se desborde y obtenga una barra de desplazamiento; debería ser suficiente para hacer algo interesante sin jugar demasiado, pero lo suficientemente corto como para mantener la atención de todos para una demostración rápida. Por ejemplo, con un poco de reformateo, el servidor web de ejemplo debería poder caber (sin contar los datos).
¡Muéstranos tu código Go!
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
}
}
}
Este es un proxy web que escribí para proporcionar acceso no autenticado a un servicio web que requería autenticación básica de 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))
}
Esto hace que un PNG (en stdout) de un reloj muestre la hora actual. Casi no tiene golf para caber en 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);
}
Ejecútelo como
8.out > clock.png
¿Te das cuenta de todos esos moldes float64? NUNCA HE VISTO un lenguaje tan estricto como Ir sobre tipos.
Este es el mismo código corregido con go fix
(y algunos ajustes manuales) y luego formateado automáticamente con 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)
}
OK, voy a poner la bola en marcha. Aquí está mi primer programa Go. Es un servidor de chat muy primitivo, y cabe en 30 líneas de 80 caracteres si lo comprimí un poco; formateado con gofmt
, es 60 líneas. Escucha en un puerto codificado (4242), básicamente no maneja ningún error, y no maneja la desconexión del cliente que no sea detener la lectura de un cliente si se produce 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 } } }
Construye y ejecuta con:
$ 6g server.go $ 6l -o server server.6 $ ./server
Y luego en algunas otras terminales, conéctese con
$ nc localhost 4242
Realmente me gustan los canales de Go y la declaración de select
, así que aquí hay algo que muestra lo fácil que es expresar el concepto "ve y obtén la mayor cantidad de cosas posible en un determinado momento".
Esto genera tantos números aleatorios como sea posible en 300 milisegundos y devuelve el mayor generado en ese 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
}
}
}
}