go

go - Ve ejemplos y modismos



(25)

Ve y obtén tu reputación de stackoverflow

Esta es una traducción de esta respuesta .

package main import ( "json" "fmt" "http" "os" "strings" ) func die(message string) { fmt.Printf("%s./n", message); os.Exit(1); } func main() { kinopiko_flair := "https://stackoverflow.com/users/flair/181548.json" response, _, err := http.Get(kinopiko_flair) if err != nil { die(fmt.Sprintf("Error getting %s", kinopiko_flair)) } var nr int const buf_size = 0x1000 buf := make([]byte, buf_size) nr, err = response.Body.Read(buf) if err != nil && error != os.EOF { die(fmt.Sprintf("Error reading response: %s", err.String())) } if nr >= buf_size { die ("Buffer overrun") } response.Body.Close() json_text := strings.Split(string(buf), "/000", 2) parsed, ok, errtok := json.StringToJson(json_text[0]) if ! ok { die(fmt.Sprintf("Error parsing JSON %s at %s", json_text, errtok)) } fmt.Printf("Your stackoverflow.com reputation is %s/n", parsed.Get ("reputation")) }

Gracias a Scott Wales por su ayuda con .Read ().

Esto parece bastante torpe todavía, con las dos cadenas y dos búferes, así que si algún experto de Go tiene algún consejo, házmelo saber.

No hay un montón de código Go para aprender el idioma, y ​​estoy seguro de que no soy el único que está experimentando con él. Por lo tanto, si descubrió algo interesante sobre el idioma, publique un ejemplo aquí.

También estoy buscando

  • formas idiomáticas de hacer cosas en Go,
  • Estilo de pensamiento C / C ++ "portado" a Go,
  • errores comunes sobre la sintaxis,
  • algo interesante, realmente.

Devolviendo un canal

Este es un verdadero modismo que es bastante importante: cómo alimentar datos en un canal y cerrarlos después. Con esto puedes hacer iteradores simples (ya que el rango aceptará un canal) o filtros.

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


¿Viste esta charla ? Muestra muchas cosas interesantes que puedes hacer (final de la charla)


Al importar paquetes, puede redefinir el nombre a cualquier cosa que desee:

package main import f "fmt" func main() { f.Printf("Hello World/n"); }


Aquí hay un buen ejemplo de iota de la publicación de Kinopiko :

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 (!)



Aquí hay un modismo de la página Effective Go

switch { case ''0'' <= c && c <= ''9'': return c - ''0'' case ''a'' <= c && c <= ''f'': return c - ''a'' + 10 case ''A'' <= c && c <= ''F'': return c - ''A'' + 10 } return 0

La instrucción switch cambia a true cuando no se da expresión. Entonces esto es equivalente a

if ''0'' <= c && c <= ''9'' { return c-''0''; } else if ''a'' <= c && c <= ''f'' { return c - ''a'' + 10; } else if ''A'' <= c && c <= ''F'' { return c - ''A'' + 10; } return 0;

Por el momento, la versión del interruptor me parece un poco más limpia.


De la respuesta de James Antill :

foo := <-ch; // This blocks. foo, ok := <-ch; // This returns immediately.

Además, una posible trampa: la sutil diferencia entre los operadores de recepción y envío:

a <- ch; // sends ch to channel a <-ch; // reads from channel ch


Esta es una implementación de una pila. Ilustra cómo agregar métodos a un tipo.

Quería hacer que la pila formara parte de ella en una división y usar las propiedades de la división, pero aunque conseguí que funcionara sin el type , no pude ver la sintaxis para definir una división con un type .

package main import "fmt"; import "os"; const stack_max = 100; type Stack2 struct { 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 (); }


Hay muchos programas pequeños en test en el directorio principal. Ejemplos:

  • peano.go imprime factoriales.
  • hilbert.go tiene alguna multiplicación de matriz.
  • iota.go tiene ejemplos de lo extraño de iota.

Hay un sistema make configurado que puede usar en $ GOROOT / src

Configura tu archivo MAKE con

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

A continuación, puede usar las herramientas de prueba automatizadas ejecutando make test o agregando el paquete y los objetos compartidos de cgo a su $ GOROOT con make install.


He visto a un par de personas quejándose sobre el ciclo for, en la línea de "¿por qué deberíamos decir i = 0; i < len; i++ en este día y edad?".

No estoy de acuerdo, me gusta el constructo. Puedes usar la versión larga si lo deseas, pero el idiomático Go es

var a = []int{1,2,3}; for i, v := range a { fmt.Println(i, v); }

La construcción del for .. range recorre todos los elementos y proporciona dos valores: el índice i el valor v .

range también funciona en mapas y canales.

Aún así, si no le gusta en cualquier forma, puede definir each , map , etc. en unas pocas líneas:

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, value int)) { for i, v := range a { fn(i, v); } } func main() { var a = IntArr([]int{2,0,0,9}); // create int slice and cast to IntArr var fnPrint = func (i, v int) { fmt.Println(i, ":", v); }; // create a function a.each(fnPrint); // call on each element }

huellas dactilares

0 : 2 1 : 0 2 : 0 3 : 9

Estoy empezando a gustar Ir mucho :)


Los archivos de objetos Go incluyen un encabezado de texto claro:

jurily@jurily ~/workspace/go/euler31 $ 6g euler31.go jurily@jurily ~/workspace/go/euler31 $ cat euler31.6 amd64 exports automatically generated from euler31.go in package "main" import $$ // exports package 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·1 struct { ? int } $$ ! <binary segment>


Me gusta que pueda redefinir tipos, incluidas primitivas como int, tantas veces como desee y adjuntar diferentes métodos. Como definir un tipo RomanNumeral:

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, " ", 0) var aRoman = strings.Split(numRoman, " ", 0) type TextNumber int type RomanNumber int 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)); }

Que imprime

Number: 5 five V

La llamada RomanNumber() es esencialmente un elenco, redefine el tipo int como un tipo más específico de int. Y Println() llama a String() detrás de las escenas.


Otra cosa interesante en Go es ese godoc . Puede ejecutarlo como un servidor web en su computadora utilizando

godoc -http=:8080

donde 8080 es el número de puerto, y todo el sitio web en golang.org está disponible en localhost:8080 .


Puede intercambiar variables por asignación paralela:

x, y = y, x // or in an array a[j], a[i] = a[i], a[j]

simple pero efectivo


Tiempo de espera para lecturas de canales:

ticker := time.NewTicker(ns); select { case v := <- chan_target: do_something_with_v; case <- ticker.C: handle_timeout; }

Robado de Davies Liu .


Una pila basada en la otra respuesta, pero que usa una división para no tener límite de tamaño.

package main import "fmt" import "os" type Stack2 struct { // 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() }


Tipo de interruptores :

switch i := x.(type) { case nil: printString("x is nil"); case int: printInt(i); // i is an int case float: printFloat(i); // i is a float case func(int) float: printFunction(i); // i is a function case bool, string: printString("type is bool or string"); // i is an interface{} default: printString("don''t know the type"); }


Declaraciones diferidas

Una instrucción "diferir" invoca una función cuya ejecución se aplaza hasta el momento en que la función circundante retorna.

DeferStmt = "diferir" Expresión.

La expresión debe ser una llamada a función o método. Cada vez que se ejecuta la instrucción "diferir", los parámetros de la llamada a la función se evalúan y se guardan de nuevo, pero la función no se invoca. Las llamadas a funciones diferidas se ejecutan en orden LIFO inmediatamente antes de que regrese la función circundante, pero después de que se hayan evaluado los valores de retorno, si los hay.


lock(l); defer unlock(l); // unlocking happens before surrounding function returns // prints 3 2 1 0 before surrounding function returns for i := 0; i <= 3; i++ { defer fmt.Print(i); }

Actualizar:

defer es ahora también la forma idiomática de manejar el panic de una manera exception-like :

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


Llamando al código c de go

Es posible acceder al nivel inferior de go mediante el uso del tiempo de ejecución c.

Las funciones C están en la forma

void package·function(...)

(tenga en cuenta que el separador de puntos es un carácter unicode) donde los argumentos pueden ser básicos, vaya a tipos, sectores, cadenas, etc. Para devolver una llamada de valor

FLUSH(&ret)

(puede devolver más de un valor)

Por ejemplo, para crear una función

package foo bar( a int32, b string )(c float32 ){ c = 1.3 + float32(a - int32(len(b)) }

en C usas

#include "runtime.h" void foo·bar(int32 a, String b, float32 c){ c = 1.3 + a - b.len; FLUSH(&c); }

Tenga en cuenta que todavía debe declarar la función en un archivo go, y que usted mismo tendrá que ocuparse de la memoria. No estoy seguro si es posible llamar a bibliotecas externas usando esto, puede ser mejor usar cgo.

Consulte $ GOROOT / src / pkg / runtime para ver ejemplos usados ​​en el tiempo de ejecución.

Consulte también esta respuesta para vincular el código de C ++ con go.


Parámetros de resultados nombrados

Los "parámetros" de retorno o resultado de una función Go pueden recibir nombres y usarse como variables regulares, al igual que los parámetros entrantes. Cuando se nombran, se inicializan a los valores cero para sus tipos cuando comienza la función; si la función ejecuta una instrucción return sin argumentos, los valores actuales de los parámetros de resultado se utilizan como valores devueltos.

Los nombres no son obligatorios, pero pueden hacer que el código sea más breve y claro: son documentación. Si nombramos los resultados de nextInt, resulta obvio cuál devuelto int es cuál.

func nextInt(b []byte, pos int) (value, nextPos int) {

Debido a que los resultados nombrados se inicializan y se vinculan a un retorno sin adornos, pueden simplificar y aclarar. Aquí hay una versión de io.ReadFull que los usa bien:

func ReadFull(r Reader, buf []byte) (n int, err os.Error) { for len(buf) > 0 && err == nil { var nr int; nr, err = r.Read(buf); n += nr; buf = buf[nr:len(buf)]; } return; }


/* * 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 { return 1 } if amount < 0 { return 0 } if max <= 0 && amount >= 1 { return 0 } // recursion works as expected return howmany(amount, max-1) + howmany(amount-coin[max], max) } func main() { fmt.Println(howmany(200, len(coin)-1)) }


const ever = true; for ever { //infinite loop }


for { v := <-ch; if closed(ch) { break } fmt.Println(v) }

Dado que range comprueba automáticamente si hay un canal cerrado, podemos acortarlo a esto:

for v := range ch { fmt.Println(v) }