Merge pull request #969 from gitnacho/master-mx

Master mx
This commit is contained in:
Adam Bard 2015-08-31 09:15:48 +09:00
commit f777a1578c

View File

@ -1,150 +1,191 @@
--- ---
name: Go
category: language
language: Go language: Go
lang: es-es lang: es-es
filename: learngo-es.go filename: learngo-es.go
contributors: contributors:
- ["Sonia Keys", "https://github.com/soniakeys"] - ["Sonia Keys", "https://github.com/soniakeys"]
- ["Christopher Bess", "https://github.com/cbess"]
- ["Jesse Johnson", "https://github.com/holocronweaver"]
- ["Quint Guvernator", "https://github.com/qguv"]
- ["Jose Donizetti", "https://github.com/josedonizetti"]
- ["Alexej Friesen", "https://github.com/heyalexej"]
translators: translators:
- ["Adrian Espinosa", "http://www.adrianespinosa.com"] - ["Adrian Espinosa", "http://www.adrianespinosa.com"]
- ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Jesse Johnson", "https://github.com/holocronweaver"]
- ["Nacho Pacheco -- Feb/2015", "https://github.com/gitnacho"]
--- ---
Go fue creado por la necesidad de hacer el trabajo rápidamente. No es Go fue creado por la necesidad de hacer el trabajo rápidamente. No es la
la última tendencia en informática, pero es la forma nueva y más última tendencia en informática, pero es la forma nueva y más rápida de
rápida de resolver problemas reales. resolver problemas reales.
Tiene conceptos familiares de lenguajes imperativos con tipado Tiene conceptos familiares de lenguajes imperativos con tipado estático.
estático. Es rápido compilando y rápido al ejecutar, añade una Es rápido compilando y rápido al ejecutar, añade una concurrencia fácil de
concurrencia fácil de entender para las CPUs de varios núcleos de hoy entender para las CPUs de varios núcleos de hoy día, y tiene
en día, y tiene características que ayudan con la programación a gran características que ayudan con la programación a gran escala.
escala.
Go viene con una librería estándar muy buena y una comunidad entusiasta. Go viene con una biblioteca estándar muy buena y una entusiasta comunidad.
```go ```go
// Comentario de una sola línea // Comentario de una sola línea
/* Comentario /* Comentario
multilínea */ multilínea */
// La cláusula package aparece al comienzo de cada archivo fuente. // La cláusula `package` aparece al comienzo de cada fichero fuente.
// Main es un nombre especial que declara un ejecutable en vez de una librería. // `main` es un nombre especial que declara un ejecutable en vez de una
// biblioteca.
package main package main
// La declaración Import declara los paquetes de librerías // La instrucción `import` declara los paquetes de bibliotecas referidos
// referenciados en este archivo. // en este fichero.
import ( import (
"fmt" // Un paquete en la librería estándar de Go. "fmt" // Un paquete en la biblioteca estándar de Go.
"net/http" // Sí, un servidor web! "io/ioutil" // Implementa algunas útiles funciones de E/S.
m "math" // Biblioteca de matemáticas con alias local m.
"net/http" // Sí, ¡un servidor web!
"strconv" // Conversiones de cadenas. "strconv" // Conversiones de cadenas.
m "math" // Librería matemáticas con alias local m.
) )
// Definición de una función. Main es especial. Es el punto de // Definición de una función. `main` es especial. Es el punto de entrada
// entrada para el ejecutable. Te guste o no, Go utiliza llaves. // para el ejecutable. Te guste o no, Go utiliza llaves.
func main() { func main() {
// Println imprime una línea a stdout. // Println imprime una línea a stdout.
// Cualificalo con el nombre del paquete, fmt. // Cualificalo con el nombre del paquete, fmt.
fmt.Println("Hello world!") fmt.Println("¡Hola mundo!")
// Llama a otra función de este paquete. // Llama a otra función de este paquete.
beyondHello() másAlláDelHola()
} }
// Las funciones llevan parámetros entre paréntesis. // Las funciones llevan parámetros entre paréntesis.
// Si no hay parámetros, los paréntesis siguen siendo obligatorios. // Si no hay parámetros, los paréntesis siguen siendo obligatorios.
func beyondHello() { func másAlláDelHola() {
var x int // Declaración de una variable. var x int // Declaración de una variable.
// Las variables se deben declarar antes de utilizarlas. // Las variables se deben declarar antes de utilizarlas.
x = 3 // Asignación de variables. x = 3 // Asignación de variable.
// Declaración "corta" con := para inferir el tipo, declarar y asignar. // Declaración "corta" con := para inferir el tipo, declarar y asignar.
y := 4 y := 4
sum, prod := learnMultiple(x, y) // Función devuelve dos valores. suma, producto := aprendeMúltiple(x, y) // La función devuelve dos
fmt.Println("sum:", sum, "prod:", prod) // Simple salida. // valores.
learnTypes() // < y minutes, learn more! fmt.Println("suma:", suma, "producto:", producto) // Simple salida.
aprendeTipos() // < y minutos, ¡aprende más!
} }
// Las funciones pueden tener parámetros y (múltiples!) valores de retorno. // Las funciones pueden tener parámetros y (¡múltiples!) valores de
func learnMultiple(x, y int) (sum, prod int) { // retorno.
return x + y, x * y // Devolver dos valores. func aprendeMúltiple(x, y int) (suma, producto int) {
return x + y, x * y // Devuelve dos valores.
} }
// Algunos tipos incorporados y literales. // Algunos tipos incorporados y literales.
func learnTypes() { func aprendeTipos() {
// La declaración corta suele darte lo que quieres. // La declaración corta suele darte lo que quieres.
s := "Learn Go!" // tipo cadena s := "¡Aprende Go!" // tipo cadena.
s2 := `Un tipo cadena "puro" puede incluir s2 := `Un tipo cadena "puro" puede incluir
saltos de línea.` // mismo tipo cadena saltos de línea.` // mismo tipo cadena
// Literal no ASCII. Los fuentes de Go son UTF-8. // Literal no ASCII. Los ficheros fuente de Go son UTF-8.
g := 'Σ' // Tipo rune, un alias de int32, alberga un punto unicode. g := 'Σ' // Tipo rune, un alias de int32, alberga un carácter unicode.
f := 3.14195 // float64, el estándar IEEE-754 de coma flotante 64-bit. f := 3.14195 // float64, el estándar IEEE-754 de coma flotante 64-bit.
c := 3 + 4i // complex128, representado internamente por dos float64. c := 3 + 4i // complex128, representado internamente por dos float64.
// Sintaxis Var con inicializadores. // Sintaxis Var con iniciadores.
var u uint = 7 // Sin signo, pero la implementación depende del var u uint = 7 // Sin signo, pero la implementación depende del tamaño
// tamaño como en int. // como en int.
var pi float32 = 22. / 7 var pi float32 = 22. / 7
// Sintáxis de conversión con una declaración corta. // Sintáxis de conversión con una declaración corta.
n := byte('\n') // byte es un alias de uint8. n := byte('\n') // byte es un alias para uint8.
// Los Arrays tienen un tamaño fijo a la hora de compilar. // Los Arreglos tienen un tamaño fijo a la hora de compilar.
var a4 [4]int // Un array de 4 ints, inicializados a 0. var a4 [4]int // Un arreglo de 4 ints, iniciados a 0.
a3 := [...]int{3, 1, 5} // Un array de 3 ints, inicializados como se indica. a3 := [...]int{3, 1, 5} // Un arreglo iniciado con un tamaño fijo de tres
// elementos, con valores 3, 1 y 5.
// Los Slices tienen tamaño dinámico. Los arrays y slices tienen sus ventajas // Los Sectores tienen tamaño dinámico. Los arreglos y sectores tienen
// y desventajas pero los casos de uso para los slices son más comunes. // sus ventajas y desventajas pero los casos de uso para los sectores
// son más comunes.
s3 := []int{4, 5, 9} // Comparar con a3. No hay puntos suspensivos. s3 := []int{4, 5, 9} // Comparar con a3. No hay puntos suspensivos.
s4 := make([]int, 4) // Asigna slices de 4 ints, inicializados a 0. s4 := make([]int, 4) // Asigna sectores de 4 ints, iniciados a 0.
var d2 [][]float64 // Solo declaración, sin asignación. var d2 [][]float64 // Solo declaración, sin asignación.
bs := []byte("a slice") // Sintaxis de conversión de tipo. bs := []byte("a sector") // Sintaxis de conversión de tipo.
// Debido a que son dinámicos, los sectores pueden crecer bajo demanda.
p, q := learnMemory() // Declara p, q para ser un tipo puntero a int. // Para añadir elementos a un sector, se utiliza la función incorporada
// append().
// El primer argumento es el sector al que se está anexando. Comúnmente,
// la variable del arreglo se actualiza en su lugar, como en el
// siguiente ejemplo.
sec := []int{1, 2 , 3} // El resultado es un sector de longitud 3.
sec = append(sec, 4, 5, 6) // Añade 3 elementos. El sector ahora tiene una
// longitud de 6.
fmt.Println(sec) // El sector actualizado ahora es [1 2 3 4 5 6]
// Para anexar otro sector, en lugar de la lista de elementos atómicos
// podemos pasar una referencia a un sector o un sector literal como
// este, con elipsis al final, lo que significa tomar un sector y
// desempacar sus elementos, añadiéndolos al sector sec.
sec = append(sec, []int{7, 8, 9} ...) // El segundo argumento es un
// sector literal.
fmt.Println(sec) // El sector actualizado ahora es [1 2 3 4 5 6 7 8 9]
p, q := aprendeMemoria() // Declara p, q para ser un tipo puntero a
// int.
fmt.Println(*p, *q) // * sigue un puntero. Esto imprime dos ints. fmt.Println(*p, *q) // * sigue un puntero. Esto imprime dos ints.
// Los Maps son arrays asociativos dinámicos, como los hash o // Los Mapas son arreglos asociativos dinámicos, como los hash o
// diccionarios de otros lenguajes. // diccionarios de otros lenguajes.
m := map[string]int{"three": 3, "four": 4} m := map[string]int{"tres": 3, "cuatro": 4}
m["one"] = 1 m["uno"] = 1
// Las variables no utilizadas en Go producen error. // Las variables no utilizadas en Go producen error.
// El guión bajo permite "utilizar" una variable, pero descartar su valor. // El guión bajo permite "utilizar" una variable, pero descartar su
// valor.
_, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs
// Esto cuenta como utilización de variables. // Esto cuenta como utilización de variables.
fmt.Println(s, c, a4, s3, d2, m) fmt.Println(s, c, a4, s3, d2, m)
learnFlowControl() // Vuelta al flujo. aprendeControlDeFlujo() // Vuelta al flujo.
} }
// Go posee recolector de basura. Tiene puntero pero no aritmética de // Es posible, a diferencia de muchos otros lenguajes tener valores de
// punteros. Puedes cometer un errores con un puntero nil, pero no // retorno con nombre en las funciones.
// Asignar un nombre al tipo que se devuelve en la línea de declaración de
// la función nos permite volver fácilmente desde múltiples puntos en una
// función, así como sólo utilizar la palabra clave `return`, sin nada
// más.
func aprendeRetornosNombrados(x, y int) (z int) {
z = x * y
return // aquí z es implícito, porque lo nombramos antes.
}
// Go posee recolector de basura. Tiene punteros pero no aritmética de
// punteros. Puedes cometer errores con un puntero nil, pero no
// incrementando un puntero. // incrementando un puntero.
func learnMemory() (p, q *int) { func aprendeMemoria() (p, q *int) {
// q y p tienen un tipo puntero a int. // Los valores de retorno nombrados q y p tienen un tipo puntero
p = new(int) // Función incorporada que asigna memoria. // a int.
// La asignación de int se inicializa a 0, p ya no es nil. p = new(int) // Función incorporada que reserva memoria.
s := make([]int, 20) // Asigna 20 ints a un solo bloque de memoria. // La asignación de int se inicia a 0, p ya no es nil.
s[3] = 7 // Asignar uno de ellos. s := make([]int, 20) // Reserva 20 ints en un solo bloque de memoria.
r := -2 // Declarar otra variable local. s[3] = 7 // Asigna uno de ellos.
r := -2 // Declara otra variable local.
return &s[3], &r // & toma la dirección de un objeto. return &s[3], &r // & toma la dirección de un objeto.
} }
func expensiveComputation() float64 { func cálculoCaro() float64 {
return m.Exp(10) return m.Exp(10)
} }
func learnFlowControl() { func aprendeControlDeFlujo() {
// La declaración If requiere llaves, pero no paréntesis. // La declaración If requiere llaves, pero no paréntesis.
if true { if true {
fmt.Println("told ya") fmt.Println("ya relatado")
} }
// El formato está estandarizado por el comando "go fmt." // El formato está estandarizado por la orden "go fmt."
if false { if false {
// Pout. // Abadejo.
} else { } else {
// Gloat. // Relamido.
} }
// Utiliza switch preferiblemente para if encadenados. // Utiliza switch preferentemente para if encadenados.
x := 42.0 x := 42.0
switch x { switch x {
case 0: case 0:
@ -155,35 +196,88 @@ func learnFlowControl() {
// No llega. // No llega.
} }
// Como if, for no utiliza paréntesis tampoco. // Como if, for no utiliza paréntesis tampoco.
// Variables declaradas en for y if son locales de su ámbito local. // Variables declaradas en for e if son locales a su ámbito.
for x := 0; x < 3; x++ { // ++ es una sentencia. for x := 0; x < 3; x++ { // ++ es una instrucción.
fmt.Println("iteration", x) fmt.Println("iteración", x)
} }
// x == 42 aqui. // aquí x == 42.
// For es la única sentencia de bucle en Go, pero tiene formas alternativas. // For es la única instrucción de bucle en Go, pero tiene formas
// alternativas.
for { // Bucle infinito. for { // Bucle infinito.
break // Solo bromeaba! break // ¡Solo bromeaba!
continue // No llega. continue // No llega.
} }
// Como en for, := en una sentencia if significa declarar y asignar primero,
// luego comprobar y > x. // Puedes usar `range` para iterar en un arreglo, un sector, una
if y := expensiveComputation(); y > x { // cadena, un mapa o un canal.
// `range` devuelve o bien, un canal o de uno a dos valores (arreglo,
// sector, cadena y mapa).
for clave, valor := range map[string]int{"uno": 1, "dos": 2, "tres": 3} {
// por cada par en el mapa, imprime la clave y el valor
fmt.Printf("clave=%s, valor=%d\n", clave, valor)
}
// Como en for, := en una instrucción if significa declarar y asignar
// primero, luego comprobar y > x.
if y := cálculoCaro(); y > x {
x = y x = y
} }
// Los literales de funciones son "closures". // Las funciones literales son "cierres".
xBig := func() bool { granX := func() bool {
return x > 100 // Referencia a x declarada encima de la sentencia switch. return x > 100 // Referencia a x declarada encima de la instrucción
// switch.
} }
fmt.Println("xBig:", xBig()) // verdadero (la última vez asignamos 1e6 a x). fmt.Println("granX:", granX()) // cierto (la última vez asignamos
x /= m.Exp(9) // Esto lo hace x == e. // 1e6 a x).
fmt.Println("xBig:", xBig()) // Ahora es falso. x /= 1.3e3 // Esto hace a x == 1300
fmt.Println("granX:", granX()) // Ahora es falso.
// Es más las funciones literales se pueden definir y llamar en línea,
// actuando como un argumento para la función, siempre y cuando:
// a) la función literal sea llamada inmediatamente (),
// b) el tipo del resultado sea del tipo esperado del argumento
fmt.Println("Suma dos números + doble: ",
func(a, b int) int {
return (a + b) * 2
}(10, 2)) // Llamada con argumentos 10 y 2
// => Suma dos números + doble: 24
// Cuando lo necesites, te encantará. // Cuando lo necesites, te encantará.
goto love goto encanto
love: encanto:
learnInterfaces() // Buen material dentro de poco! aprendeFunciónFábrica() // func devolviendo func es divertido(3)(3)
aprendeADiferir() // Un rápido desvío a una importante palabra clave.
aprendeInterfaces() // ¡Buen material dentro de poco!
}
func aprendeFunciónFábrica() {
// Las dos siguientes son equivalentes, la segunda es más práctica
fmt.Println(instrucciónFábrica("día")("Un bello", "de verano"))
d := instrucciónFábrica("atardecer")
fmt.Println(d("Un hermoso", "de verano"))
fmt.Println(d("Un maravilloso", "de verano"))
}
// Los decoradores son comunes en otros lenguajes. Lo mismo se puede hacer
// en Go con funciónes literales que aceptan argumentos.
func instrucciónFábrica(micadena string) func(antes, después string) string {
return func(antes, después string) string {
return fmt.Sprintf("¡%s %s %s!", antes, micadena, después) // nueva cadena
}
}
func aprendeADiferir() (ok bool) {
// las instrucciones diferidas se ejecutan justo antes de que la
// función regrese.
defer fmt.Println("las instrucciones diferidas se ejecutan en orden inverso (PEPS).")
defer fmt.Println("\nEsta línea se imprime primero debido a que")
// Defer se usa comunmente para cerrar un fichero, por lo que la
// función que cierra el fichero se mantiene cerca de la función que lo
// abrió.
return true
} }
// Define Stringer como un tipo interfaz con un método, String. // Define Stringer como un tipo interfaz con un método, String.
@ -191,136 +285,166 @@ type Stringer interface {
String() string String() string
} }
// Define pair como un struct con dos campos int, x e y. // Define par como una estructura con dos campos int, x e y.
type pair struct { type par struct {
x, y int x, y int
} }
// Define un método del tipo pair. Pair ahora implementa Stringer. // Define un método en el tipo par. Par ahora implementa a Stringer.
func (p pair) String() string { // p se llama "recibidor" func (p par) String() string { // p se conoce como el "receptor"
// Sprintf es otra función pública del paquete fmt. // Sprintf es otra función pública del paquete fmt.
// La sintaxis con punto referencia campos de p. // La sintaxis con punto se refiere a los campos de p.
return fmt.Sprintf("(%d, %d)", p.x, p.y) return fmt.Sprintf("(%d, %d)", p.x, p.y)
} }
func learnInterfaces() { func aprendeInterfaces() {
// La sintaxis de llaves es un "literal struct". Evalúa a un struct // La sintaxis de llaves es una "estructura literal". Evalúa a una
// inicializado. La sintaxis := declara e inicializa p a este struct. // estructura iniciada. La sintaxis := declara e inicia p a esta
p := pair{3, 4} // estructura.
fmt.Println(p.String()) // Llamar al método String de p, de tipo pair. p := par{3, 4}
var i Stringer // Declarar i como interfaz tipo Stringer. fmt.Println(p.String()) // Llama al método String de p, de tipo par.
i = p // Válido porque pair implementa Stringer. var i Stringer // Declara i como interfaz de tipo Stringer.
// Llamar al metodo String de i, de tipo Stringer. Misma salida que arriba. i = p // Válido porque par implementa Stringer.
// Llama al metodo String de i, de tipo Stringer. Misma salida que
// arriba.
fmt.Println(i.String()) fmt.Println(i.String())
// Las funciones en el paquete fmt llaman al método String para // Las funciones en el paquete fmt llaman al método String para
// preguntar a un objeto por una versión imprimible de si mismo. // consultar un objeto por una representación imprimible de si
fmt.Println(p) // Salida igual que arriba. Println llama al método String. // mismo.
fmt.Println(p) // Salida igual que arriba. Println llama al método
// String.
fmt.Println(i) // Salida igual que arriba. fmt.Println(i) // Salida igual que arriba.
aprendeNúmeroVariableDeParámetros("¡gran", "aprendizaje", "aquí!")
learnVariadicParams("great", "learning", "here!")
} }
// Las funciones pueden tener número variable de argumentos. // Las funciones pueden tener número variable de argumentos.
func learnVariadicParams(myStrings ...interface{}) { func aprendeNúmeroVariableDeParámetros(misCadenas ...interface{}) {
// Iterar cada valor de la variadic. // Itera en cada valor de los argumentos variables.
for _, param := range myStrings { // El espacio en blanco aquí omite el índice del argumento arreglo.
fmt.Println("param:", param) for _, parámetro := range misCadenas {
fmt.Println("parámetro:", parámetro)
} }
// Pasar valor variadic como parámetro variadic. // Pasa el valor de múltiples variables como parámetro variadic.
fmt.Println("params:", fmt.Sprintln(myStrings...)) fmt.Println("parámetros:", fmt.Sprintln(misCadenas...))
aprendeManejoDeError()
learnErrorHandling()
} }
func learnErrorHandling() { func aprendeManejoDeError() {
// ", ok" forma utilizada para saber si algo funcionó o no. // ", ok" forma utilizada para saber si algo funcionó o no.
m := map[int]string{3: "three", 4: "four"} m := map[int]string{3: "tres", 4: "cuatro"}
if x, ok := m[1]; !ok { // ok será falso porque 1 no está en el map. if x, ok := m[1]; !ok { // ok será falso porque 1 no está en el mapa.
fmt.Println("no one there") fmt.Println("nada allí")
} else { } else {
fmt.Print(x) // x sería el valor, si estuviera en el map. fmt.Print(x) // x sería el valor, si estuviera en el mapa.
} }
// Un valor de error comunica más información sobre el problema aparte de "ok". // Un valor de error comunica más información sobre el problema aparte
if _, err := strconv.Atoi("non-int"); err != nil { // _ descarta el valor // de "ok".
// Imprime "strconv.ParseInt: parsing "non-int": invalid syntax". if _, err := strconv.Atoi("no-int"); err != nil { // _ descarta el
// valor
// Imprime "strconv.ParseInt: parsing "no-int": invalid syntax".
fmt.Println(err) fmt.Println(err)
} }
// Revisarmeos las interfaces más tarde. Mientras tanto, // Revisaremos las interfaces más adelante. Mientras tanto...
learnConcurrency() aprendeConcurrencia()
} }
// c es un canal, un objeto de comunicación de concurrencia segura. // c es un canal, un objeto de comunicación concurrente seguro.
func inc(i int, c chan int) { func inc(i int, c chan int) {
c <- i + 1 // <- es el operador "enviar" cuando un canal aparece a la izquierda. c <- i + 1 // <- es el operador "enviar" cuando aparece un canal a la
// izquierda.
} }
// Utilizaremos inc para incrementar algunos números concurrentemente. // Utilizaremos inc para incrementar algunos números concurrentemente.
func learnConcurrency() { func aprendeConcurrencia() {
// Misma función make utilizada antes para crear un slice. Make asigna e // Misma función make utilizada antes para crear un sector. Make asigna
// inicializa slices, maps, y channels. // e inicia sectores, mapas y canales.
c := make(chan int) c := make(chan int)
// Iniciar tres goroutines concurrentes. Los números serán incrementados // Inicia tres rutinasgo concurrentes. Los números serán incrementados
// concurrentemente, quizás en paralelo si la máquina es capaz y // concurrentemente, quizás en paralelo si la máquina es capaz y está
// está correctamente configurada. Las tres envían al mismo channel. // correctamente configurada. Las tres envían al mismo canal.
go inc(0, c) // go es una sentencia que inicia una nueva goroutine. go inc(0, c) // go es una instrucción que inicia una nueva rutinago.
go inc(10, c) go inc(10, c)
go inc(-805, c) go inc(-805, c)
// Leer los tres resultados del channel e imprimirlos. // Lee los tres resultados del canal y los imprime.
// No se puede saber en que orden llegarán los resultados! // ¡No se puede saber en que orden llegarán los resultados!
fmt.Println(<-c, <-c, <-c) // Channel a la derecha, <- es el operador "recibir". fmt.Println(<-c, <-c, <-c) // Canal a la derecha, <- es el operador
// "recibe".
cs := make(chan string) // Otro channel, este gestiona cadenas. cs := make(chan string) // Otro canal, este gestiona cadenas.
ccs := make(chan chan string) // Un channel de cadenas de channels. ccs := make(chan chan string) // Un canal de canales cadena.
go func() { c <- 84 }() // Iniciar una nueva goroutine solo para go func() { c <- 84 }() // Inicia una nueva rutinago solo para
// enviar un valor. // enviar un valor.
go func() { cs <- "wordy" }() // Otra vez, para cs en esta ocasión. go func() { cs <- "verboso" }() // Otra vez, para cs en esta ocasión.
// Select tiene una sintáxis parecida a la sentencia switch pero // Select tiene una sintáxis parecida a la instrucción switch pero cada
// cada caso involucra una operacion de channels. Selecciona un caso // caso involucra una operacion con un canal. Selecciona un caso de
// de forma aleatoria de los casos que están listos para comunicarse. // forma aleatoria de los casos que están listos para comunicarse.
select { select {
case i := <-c: // El valor recibido puede ser asignado a una variable, case i := <-c: // El valor recibido se puede asignar a una variable,
fmt.Printf("it's a %T", i) fmt.Printf("es un %T", i)
case <-cs: // o el valor puede ser descartado. case <-cs: // o el valor se puede descartar.
fmt.Println("it's a string") fmt.Println("es una cadena")
case <-ccs: // Channel vacío, no está listo para la comunicación. case <-ccs: // Canal vacío, no está listo para la comunicación.
fmt.Println("didn't happen.") fmt.Println("no sucedió.")
} }
// En este punto un valor fue devuelvto de c o cs. Uno de las dos // En este punto un valor fue devuelto de c o cs. Una de las dos
// goroutines que se iniciaron se ha completado, la otrá permancerá // rutinasgo que se iniciaron se ha completado, la otrá permancerá
// bloqueada. // bloqueada.
learnWebProgramming() // Go lo hace. Tu también quieres hacerlo. aprendeProgramaciónWeb() // Go lo hace. Tú también quieres hacerlo.
} }
// Una simple función del paquete http inicia un servidor web. // Una simple función del paquete http inicia un servidor web.
func learnWebProgramming() { func aprendeProgramaciónWeb() {
// El primer parámetro de la direccinón TCP a la que escuchar. // El primer parámetro es la direccinón TCP a la que escuchar.
// El segundo parámetro es una interfaz, concretamente http.Handler. // El segundo parámetro es una interfaz, concretamente http.Handler.
err := http.ListenAndServe(":8080", pair{}) go func() {
fmt.Println(err) // no ignorar errores err := http.ListenAndServe(":8080", par{})
fmt.Println(err) // no ignora errores
}()
consultaAlServidor()
} }
// Haz pair un http.Handler implementando su único método, ServeHTTP. // Hace un http.Handler de par implementando su único método, ServeHTTP.
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (p par) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Servir datos con un método de http.ResponseWriter. // Sirve datos con un método de http.ResponseWriter.
w.Write([]byte("You learned Go in Y minutes!")) w.Write([]byte("¡Aprendiste Go en Y minutos!"))
}
func consultaAlServidor() {
resp, err := http.Get("http://localhost:8080")
fmt.Println(err)
defer resp.Body.Close()
cuerpo, err := ioutil.ReadAll(resp.Body)
fmt.Printf("\nEl servidor web dijo: `%s`\n", string(cuerpo))
} }
``` ```
## Para leer más ## Más información
La raíz de todas las cosas de Go es la [web oficial de Go](http://golang.org/). La raíz de todas las cosas sobre Go es el
Ahí puedes seguir el tutorial, jugar interactivamente y leer mucho. [sitio web oficial de Go](http://golang.org/).
Allí puedes seguir el tutorial, jugar interactivamente y leer mucho más.
La propia definición del lenguaje también es altamente La definición del lenguaje es altamente recomendada. Es fácil de leer y
recomendada. Es fácil de leer e increíblemente corta (como otras sorprendentemente corta (como la definición del lenguaje Go en estos
definiciones de lenguajes hoy en día) días).
En la lista de lectura de estudiantes de Go está el código fuente de Puedes jugar con el código en el
la librería estándar. Muy bien documentada, demuestra lo mejor de Go [parque de diversiones Go](https://play.golang.org/p/ncRC2Zevag). ¡Trata
leíble, comprendible, estilo Go y formas Go. Pincha en el nombre de de cambiarlo y ejecutarlo desde tu navegador! Ten en cuenta que puedes
una función en la documentación y te aparecerá el código fuente! utilizar [https://play.golang.org]( https://play.golang.org) como un
[REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop) para probar
cosas y el código en el navegador, sin ni siquiera instalar Go.
En la lista de lecturas para estudiantes de Go está el
[código fuente de la biblioteca estándar](http://golang.org/src/pkg/).
Ampliamente documentado, que demuestra lo mejor del legible y comprensible
Go, con su característico estilo y modismos. ¡O puedes hacer clic en un
nombre de función en [la documentación](http://golang.org/pkg/) y
aparecerá el código fuente!
Otro gran recurso para aprender Go está en
[Go con ejemplos](http://goconejemplos.com/).