├── .gitignore ├── README.md ├── ejemplos-libro ├── 02-sintaxis-basica │ ├── 01-hola-mundo.go │ ├── 02-constantes-variables.go │ ├── 03-conversion-explicita.go │ └── 04-operaciones.go ├── 03-control-de-flujo │ ├── 01-condicionales-if.go │ ├── 02-condicionales-switch.go │ ├── 03-switch-patrones.go │ ├── 04-ensombrecimiento-vars.go │ ├── 05-for-break.go │ ├── 06-for-continue.go │ └── 07-for-condicional.go ├── 04-apuntadores │ └── 04-apuntadores.go ├── 05-funciones │ ├── 01-basica.go │ ├── 02-multiple-asignacion.go │ ├── 03-identificador-vacio.go │ ├── 04-multiples-retornos-varargs.go │ ├── 05-literales-de-funcion.go │ ├── 06-mas-literales.go │ └── 07-argumentos-referencia.go ├── 06-arrays-slices │ ├── 01-arrays.go │ ├── 02-porciones.go │ ├── 03-iteración.go │ ├── 04-copia.go │ └── 05-argumentos-funciones.go ├── 07-strings │ ├── 01-uso-basico.go │ ├── 02-concatenacion.go │ └── 03-comparacion.go ├── 08-diccionarios │ ├── 01-maps.go │ ├── 02-iteracion.go │ └── 03-conjuntos.go ├── 09-organizacion-codigo │ ├── go.mod │ ├── go.sum │ ├── hola │ │ └── hola.go │ ├── main.go │ └── vendor │ │ ├── github.com │ │ └── mariomac │ │ │ ├── analizador │ │ │ ├── .gitignore │ │ │ ├── LICENSE │ │ │ ├── analizador.go │ │ │ ├── go.mod │ │ │ └── go.sum │ │ │ └── sumadormapa │ │ │ ├── LICENSE │ │ │ └── sumador │ │ │ └── suma.go │ │ └── modules.txt ├── 10-tipos │ ├── 01-definicion tipos.go │ ├── 02-tipos-funcionales.go │ ├── 03-receptores-funcion.go │ ├── 04-contador-metodos.go │ ├── 05-pseudo-enumerados.go │ └── 06-duration.go ├── 11-tipos-estructurados │ ├── 01-estructuras-y-metodos.go │ ├── 02-incrustando-structs.go │ ├── 03-estructura-vacia.go │ └── 04-opciones-funcionales.go ├── 12-interfaces │ ├── 01-uso-basico.go │ ├── 02-casting-seguro.go │ ├── 03-analisis-de-patrones.go │ ├── 04-tipado-pato.go │ └── 05-interfaz-vacia.go ├── 13-errores │ ├── 01-errors-new.go │ ├── 02-fmt-errorf.go │ ├── 03-errores-centinela.go │ ├── 04-implementaciones-error.go │ ├── 05-envoltura-errores.go │ ├── 06-envoltura-errores-structs.go │ ├── 07-panics.go │ ├── 08-defer.go │ ├── 09-panic-recover.go │ └── 10-panic-implicito.go ├── 14-entrada-salida │ ├── 010-writers.go │ ├── 020-readers.go │ ├── 030-files.go │ ├── 035-fprint-fscan.go │ ├── 040-bufio.go │ ├── 045-scanner.go │ ├── 050-ioutil.go │ ├── 060-log.go │ └── 080-reader-writer-en-buffer.go ├── 15-paralelismo-concurrencia │ ├── 01-gorrutinas.go │ ├── 02-sync-waitgroup.go │ ├── 03-motivacion-mutex.go │ ├── 04-mutex.go │ └── 05-atomic.go ├── 16-canales │ ├── 01-envio-basico.go │ ├── 02-bloqueo-deadlock.go │ ├── 03-panic-cerrado.go │ ├── 04-sin-buffer.go │ ├── 05-con-buffer.go │ ├── 06-cerrando-con-buffer.go │ ├── 07-sincronizacion.go │ ├── 08-multiples-receptores.go │ ├── 09-iterando-canal.go │ ├── 10-select.go │ ├── 11-timeouts.go │ └── 12-context-cancel.go ├── 17-servicios-web │ ├── minirest │ │ ├── minirest.go │ │ └── minirest_test.go │ └── servidor.go ├── 18-serializacion-datos │ ├── go.mod │ ├── go.sum │ ├── serialize.go │ ├── serializemap.go │ ├── serializeslice.go │ ├── xml.go │ └── yaml.go ├── 19-bases-datos │ ├── .gitignore │ ├── go.mod │ ├── go.sum │ └── main.go └── 20-testing │ ├── fact.go │ ├── fact_test.go │ ├── fibonacci.go │ └── fibonacci_test.go ├── fe-de-erratas.md └── wasm-tutorial ├── README.md ├── ejemplo-canvas ├── README.md ├── go.mod ├── go.sum ├── server.go ├── site │ ├── index.html │ ├── main.wasm │ └── wasm_exec.js └── src │ └── main.go ├── ejemplo ├── README.md ├── go.mod ├── server.go ├── site │ ├── index.html │ ├── main.wasm │ └── wasm_exec.js └── src │ └── main.go └── img ├── demo.png ├── hola.gif └── log.png /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Programación en Go 2 | 3 | Materiales complementarios al libro "Programación en Go", de la Editorial Marcombo. 4 | 5 | Autor: [Mario Macías Lloret](http://macias.info). 6 | 7 | * [Ejemplos de código del libro](./ejemplos-libro) 8 | * [Capítulo extra: Go y WebAssembly](./wasm-tutorial) 9 | * [Fe de erratas](./fe-de-erratas.md) -------------------------------------------------------------------------------- /ejemplos-libro/02-sintaxis-basica/01-hola-mundo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // la función "main" es el punto de inicio de un programa 6 | // debe situarse en el paquete "main" 7 | func main() { 8 | /* comentarios 9 | multilínea */ 10 | fmt.Println("¡Hola, geómidos!") 11 | } 12 | -------------------------------------------------------------------------------- /ejemplos-libro/02-sintaxis-basica/02-constantes-variables.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Constante global 6 | const Pi = 3.1415 7 | 8 | // variable global no inicializada (tomará el valor 0) 9 | var Global int 10 | 11 | // variable global inicializada 12 | // (por inferencia de tipos, será un int) 13 | var GlobalCounter = 2 14 | 15 | // Constantes globales agrupadas 16 | const ( 17 | TimeoutMS = 1000 18 | MaxRetries = 4 19 | FailOnErr = true 20 | ) 21 | 22 | func main() { 23 | 24 | local := "Forma preferida de declarar una variable inicializada" 25 | 26 | local = "no confundir el operador := de declaración con el = de asignación" 27 | 28 | fmt.Print("si defines pero no usas una variable local,") 29 | fmt.Println("obtendrías un error de compilación") 30 | fmt.Println(local) 31 | } 32 | -------------------------------------------------------------------------------- /ejemplos-libro/02-sintaxis-basica/03-conversion-explicita.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var numeroGrande int64 7 | var numeroPequeño int8 = 21 8 | 9 | // Go no soporta conversiones implícitas de tipos 10 | // debe, realizarse explicitamente 11 | numeroGrande = int64(numeroPequeño) 12 | 13 | fmt.Println("numeroGrande, smallnum:", numeroGrande, numeroPequeño) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/02-sintaxis-basica/04-operaciones.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | lang := 'C' 7 | 8 | fmt.Print("Los operadores de Go son similares") 9 | fmt.Printf("a los del lenguaje %c", lang) 10 | 11 | lang++ 12 | 13 | fmt.Printf(", incluso a los de %c.\n", lang) 14 | 15 | p0 := 10.1 16 | v := 1.2 17 | t := 3.2 18 | 19 | p := p0 + v*t 20 | 21 | // Printf has a generic %v to print values 22 | fmt.Printf("Dado un objeto en la posición %v ", p0) 23 | fmt.Printf("con una velocidad de %v m/s, ", v) 24 | fmt.Printf("después de %v segundos ", t) 25 | fmt.Printf("estará situado en la posición %v\n", p) 26 | } 27 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/01-condicionales-if.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | func main() { 9 | valor := rand.Int() % 2 10 | 11 | // El if-else clásico de otros lenguajes. 12 | // No se necesita paréntesis alrededor de la condición 13 | if valor == 0 { 14 | fmt.Println("valor par") 15 | } else { 16 | fmt.Println("valor impoar") 17 | } 18 | 19 | // se puede limitar el ámbito de una variable si ésta 20 | // se declara en el mismo if. Delante de la condición, 21 | // separada por punto y coma 22 | if otroValor := rand.Int(); otroValor%2 == 0 { 23 | fmt.Printf("Otro valor (%d) es par\n", otroValor) 24 | } else { 25 | fmt.Printf("Otro valor (%d) es impar\n", otroValor) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/02-condicionales-switch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | 10 | fmt.Print("La arquitectura de su procesador es ") 11 | 12 | arch := runtime.GOARCH 13 | switch arch { 14 | case "386": 15 | fmt.Println("32-bit x86") 16 | case "amd64": 17 | fmt.Println("64-bit x86") 18 | default: 19 | fmt.Println(arch) 20 | } 21 | 22 | fmt.Print("Su sistema operativo es ") 23 | 24 | // declaración de "os" en el mismo switch 25 | // limita el ámbito de la variable 26 | switch os := runtime.GOOS; os { 27 | case "darwin": 28 | fmt.Println("Mac OS X") 29 | case "linux": 30 | fmt.Println("GNU/Linux") 31 | case "hurd": 32 | fmt.Println("GNU/Hurd") 33 | default: 34 | fmt.Println(os) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/03-switch-patrones.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | 9 | fmt.Print("Escriba un carácter: ") 10 | var c int8 11 | fmt.Scanf("%c", &c) 12 | 13 | switch { 14 | case c >= 'A' && c <= 'Z': 15 | fmt.Println("Letra mayúscula") 16 | case c >= 'a' && c <= 'z': 17 | fmt.Println("Letra minúscula") 18 | case c >= '0' && c <= '9': 19 | fmt.Println("Dígito") 20 | default: 21 | fmt.Println("Ni letra ni dígito") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/04-ensombrecimiento-vars.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a := 0 7 | b := 0 8 | 9 | if true { 10 | a := 1 11 | b = 1 12 | a++ 13 | b++ 14 | } 15 | 16 | fmt.Printf("a = %d, b = %d\n", a, b) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/05-for-break.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for { 7 | fmt.Print("Salir? (s/n): ") 8 | var c rune 9 | fmt.Scanf("%c\n", &c) 10 | if c == 'S' || c == 's' { 11 | break 12 | } 13 | } 14 | fmt.Println("adiós!") 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/06-for-continue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for { 7 | fmt.Print("Salir? (s/n): ") 8 | var c rune 9 | fmt.Scanf("%c\n", &c) 10 | if c == 'N' || c == 'n' { 11 | continue 12 | } 13 | if c == 'S' || c == 's' { 14 | break 15 | } 16 | fmt.Println("carácter no reconocido") 17 | } 18 | fmt.Println("adiós!") 19 | } 20 | -------------------------------------------------------------------------------- /ejemplos-libro/03-control-de-flujo/07-for-condicional.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | 7 | var c rune 8 | for c != 'S' && c != 's' { 9 | fmt.Print("Salir? (s/n): ") 10 | fmt.Scanf("%c\n", &c) 11 | } 12 | fmt.Println("adiós!") 13 | } 14 | -------------------------------------------------------------------------------- /ejemplos-libro/04-apuntadores/04-apuntadores.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a := 1 7 | b := 2 8 | 9 | // declaración e inicialización por separado 10 | var puntero *int 11 | puntero = &a 12 | 13 | // Lectura del valor de puntero 14 | fmt.Printf("valor apuntado: %d\n", *puntero) 15 | 16 | // declaración e inicialización con inferencia de tipos 17 | // forma recomendada 18 | p := &a 19 | fmt.Printf("Primero apuntamos a %d\n", *p) 20 | 21 | // apuntando a una nueva variable 22 | p = &b 23 | fmt.Printf("Luego apuntamos a %d\n", *p) 24 | } 25 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/01-basica.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Hola(nombre string, apellido string) { 6 | fmt.Printf("Hola, %s %s!\n", nombre, apellido) 7 | } 8 | 9 | func main() { 10 | Hola("Marta", "García") 11 | Hola("Juan", "Martínez") 12 | } 13 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/02-multiple-asignacion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func unoDos() (int, int) { 6 | return 1, 2 7 | } 8 | 9 | func main() { 10 | a, b := unoDos() 11 | fmt.Printf("a = %v, b = %v\n", a, b) 12 | 13 | // intercamabiar dos valores 14 | a, b = b, a 15 | fmt.Printf("a = %v, b = %v\n", a, b) 16 | } 17 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/03-identificador-vacio.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Se puede usar el identificador vacío para evitar errores de 4 | // compilación si queremos importar un paquete que no vayamos 5 | // a usar 6 | import _ "fmt" 7 | 8 | func main() { 9 | // El identificador vacío te permite ignorar algunos valores de retorno 10 | a, _ := unoDos() 11 | 12 | // El identificador vacío también te permite ignorar errores de compilación 13 | // para variables sin usar 14 | _ = a 15 | } -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/04-multiples-retornos-varargs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Sin argumentos, sin valor de retorno 6 | func DecirHola() { 7 | fmt.Println("hola") 8 | } 9 | 10 | // multiples argumentos, un solo tipo de retorno 11 | func CoordenadaCelda(row rune, col int) string { 12 | return fmt.Sprint(row, col) 13 | } 14 | 15 | // Agrupando argumentos del mismo tipo 16 | func Max(a, b int) int { 17 | if a < b { 18 | return b 19 | } 20 | return a 21 | } 22 | 23 | // Múltiples valores de retorno 24 | func MaxMin(a, b int) (int, int) { 25 | if a < b { 26 | return b, a 27 | } 28 | return a, b 29 | } 30 | 31 | // Valores de retorno con nombre 32 | func CuentaMayusMinus(text string) (mayus int, minus int) { 33 | mayus = 0 34 | minus = 0 35 | for _, c := range text { 36 | if c >= 'A' && c <= 'Z' { 37 | mayus++ 38 | } else if c >= 'a' && c <= 'z' { 39 | minus++ 40 | } 41 | } 42 | return 43 | } 44 | 45 | // Funcion con argumentos variables 46 | func Sumatorio(n ...int) int { 47 | sum := 0 48 | for _, s := range n { 49 | sum += s 50 | } 51 | return sum 52 | } 53 | 54 | func main() { 55 | DecirHola() 56 | fmt.Println("La celda superior izquierda es ", CoordenadaCelda('A', 1)) 57 | fmt.Println("El máximo de 5 y 6 es", Max(5, 6)) 58 | 59 | ma, mi := MaxMin(4, 7) 60 | fmt.Printf("%v es mayor que %v\n", ma, mi) 61 | 62 | str := "Yo me llamo Ralph" 63 | up, lo := CuentaMayusMinus(str) 64 | fmt.Printf("%q tiene %d mayúsculas y %d minúsculas\n", str, up, lo) 65 | 66 | fmt.Println("3+4+5+6 =", Sumatorio(3, 4, 5, 6)) 67 | 68 | nums := []int{7, 8, 3} 69 | all := Sumatorio(nums...) // operador difusor (ver capítulo 6) 70 | 71 | fmt.Printf("Sumando todos los números de %v: %v\n", nums, all) 72 | } 73 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/05-literales-de-funcion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Suma(a, b int) int { 6 | return a + b 7 | } 8 | 9 | func Multiplica(a, b int) int { 10 | return a * b 11 | } 12 | 13 | func main() { 14 | var operador func(int, int) int 15 | operador = Suma 16 | fmt.Println("suma =", operador(3, 4)) 17 | operador = Multiplica 18 | fmt.Println("multiplica =", operador(3, 4)) 19 | } 20 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/06-mas-literales.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | func main() { 9 | 10 | // la variable generador puede apuntar a cualquier función sin argumentos 11 | // que retorne un int 12 | var generador func() int 13 | 14 | generador = func() int { 15 | return 0 16 | } 17 | fmt.Println("generador ceros:", generador()) 18 | 19 | // los literales de función pueden acceder a valores fuera de su ámbito 20 | cuenta := 0 21 | generador = func() int { 22 | cuenta++ 23 | return cuenta 24 | } 25 | fmt.Println("contador generador:", generador(), generador(), generador()) 26 | 27 | // generador puede apuntar a cualquier función que ya exista, si ésta 28 | // comparte la misma signatura 29 | generador = rand.Int 30 | fmt.Println("generador aleatorio:", generador()) 31 | 32 | // caso que en determinados momentos podrá ser útil: 33 | // invocar a una función inmediatamente después de definirla 34 | func(message string) { 35 | fmt.Println(message) 36 | }("goodbye!") 37 | } 38 | -------------------------------------------------------------------------------- /ejemplos-libro/05-funciones/07-argumentos-referencia.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Incrementa(a *int) { 6 | *a++ 7 | } 8 | func main() { 9 | a := 3 10 | fmt.Println("a =", a) 11 | Incrementa(&a) 12 | fmt.Println("a =", a) 13 | } 14 | -------------------------------------------------------------------------------- /ejemplos-libro/06-arrays-slices/01-arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // En Go, los vectores se tratan por valor 7 | src := [5]int{1, 2, 3, 4, 5} 8 | var dst [5]int 9 | 10 | // Eso significa que, en asignaciones, se copian 11 | dst = src 12 | src[0] = 9 13 | 14 | fmt.Printf("%v != %v", src, dst) 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/06-arrays-slices/02-porciones.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // Generalmente usaremos porciones en vez de vectores 7 | // son tratadas por referencia, y pueden tener un tamaño 8 | // variable 9 | 10 | s := []int{1, 2, 3, 4} 11 | fmt.Println("antes =", s) 12 | 13 | s = append(s, 5, 6, 7) 14 | fmt.Println("despues =", s) 15 | 16 | s1 := []int{1, 2, 3} 17 | s2 := []int{4, 5, 6} 18 | s1 = append(s1, s2...) 19 | fmt.Println("concatenación =", s1) 20 | 21 | // 1- crecimiento dinámico 22 | var sl []int 23 | fmt.Printf("length: %v. capacity: %v\n", len(sl), cap(sl)) 24 | sl = append(sl, 1, 2, 3, 4) 25 | fmt.Printf("length: %v. capacity: %v\n", len(sl), cap(sl)) 26 | sl = append(sl, 5) 27 | fmt.Printf("length: %v. capacity: %v\n", len(sl), cap(sl)) 28 | 29 | // 2- puedes definir una capacidad inicial para minimizar costes de redimensionado 30 | sl = make([]int, 0, 10) // tamaño 0, capacidad 10 31 | fmt.Printf("length: %v. capacity: %v\n", len(sl), cap(sl)) 32 | sl = append(sl, 1) 33 | fmt.Printf("length: %v. capacity: %v\n", len(sl), cap(sl)) 34 | 35 | // 3- se pueden proveer vistas 36 | base := []int{1, 0, 3, 4, 5} 37 | fmt.Println("base:", base) 38 | 39 | vista1 := base[1:3] // incluye elementos 1 y 2 40 | fmt.Println("vista 1:", vista1) 41 | vista1[0] = 2 // equivalente a base[1] = 2 42 | fmt.Println("base:", base) 43 | 44 | vista2 := base[2:] // desde índice 2 hasta el final 45 | fmt.Println("vista 2:", vista2) 46 | 47 | vista3 := base[:3] // desde el inicio hasta indice 2 48 | fmt.Println("vista 3:", vista3) 49 | 50 | vista4 := base[:] // vista de inicio a fin 51 | fmt.Println("vista 4:", vista4) 52 | 53 | } 54 | -------------------------------------------------------------------------------- /ejemplos-libro/06-arrays-slices/03-iteración.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ciudades := []string{"Tokyo", "Lleida", "Paris", "Madrid"} 7 | 8 | for i := 0; i < len(ciudades); i++ { 9 | fmt.Printf("[%d] %s\n", i, ciudades[i]) 10 | } 11 | 12 | for i, ciudad := range ciudades { 13 | fmt.Printf("[%d] %s\n", i, ciudad) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/06-arrays-slices/04-copia.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | original := []int{1, 2, 3, 4, 5} 10 | copia := make([]int, len(original)) 11 | 12 | n := copy(copia, original) 13 | fmt.Println(n, "numeros copiados:", copia) 14 | 15 | str := "😅ola" 16 | a := str[:] 17 | fmt.Println(a, reflect.TypeOf(a)) 18 | } 19 | -------------------------------------------------------------------------------- /ejemplos-libro/06-arrays-slices/05-argumentos-funciones.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Cero(vec [3]int, porc []int) { 6 | vec[0] = 0 7 | if len(porc) > 0 { 8 | porc[0] = 0 9 | } 10 | } 11 | 12 | func main() { 13 | v := [3]int{1, 2, 3} 14 | p := []int{1, 2, 3} 15 | Cero(v, p) 16 | fmt.Println("vector:", v) 17 | fmt.Println("porción:", p) 18 | } 19 | -------------------------------------------------------------------------------- /ejemplos-libro/07-strings/01-uso-basico.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | func main() { 9 | str1 := "hola mundo" 10 | fmt.Printf("%q tiene longitud %v\n", str1, len(str1)) 11 | 12 | str2 := "hola 世界" 13 | fmt.Printf("%q tiene longitud %v\n", str2, len(str2)) 14 | 15 | fmt.Printf("(de hecho, tiene %v runas)\n", utf8.RuneCountInString(str2)) 16 | 17 | barr := []byte("creando una cadena desde un array de bytes") 18 | str3 := string(barr) 19 | 20 | // Esto daría error de compilación! Las cadenas son inmutables 21 | //str3[0] = 'C' 22 | 23 | // Puedes convertir de string a un vector de bytes 24 | str4 := []byte(str3) 25 | str4[0] = 'C' 26 | 27 | // Pero no podrás asignar runas!! (constante 12416 no cabe en un byte) 28 | // str4[1] = 'む' 29 | 30 | fmt.Println(string(str4)) 31 | 32 | str5 := []rune(str3) 33 | str5[0] = 'む' 34 | fmt.Println(string(str5)) 35 | 36 | fmt.Println(`El uso del acento grave como delimitador 37 | permite escribir literales de string que pueden 38 | ocupar varias líneas e ignorar los códigos de 39 | elusión, como por ejemplo \n o \t`) 40 | 41 | fmt.Println(`Este texto se imprimirá 42 | en varias líneas 43 | y no necesitarás eludir algunos 44 | carácteres, como " or \`) 45 | } 46 | -------------------------------------------------------------------------------- /ejemplos-libro/07-strings/02-concatenacion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | str1 := "El operador" 11 | str2 := str1 + " de suma es una forma simple y rápida " + 12 | "de concatenar cadenas. " + 13 | "Pero solo puedes concatenar cadenas, y pierde" + 14 | " velocidad si se concatenan varias cadenas en" + 15 | " distintos ámbitos" 16 | fmt.Println(str2) 17 | 18 | str3 := fmt.Sprintf(`Las funciones fmt.Sprint o fmt.Sprintf 19 | permiten especificar un formato detallado para la 20 | composición de cadenas (por ejemplo %.2f), 21 | pero generalmente son más lentas que otras opciones.`, 1.1) 22 | fmt.Println(str3) 23 | 24 | var sb strings.Builder 25 | sb.WriteString("strings.Builder\n") 26 | l := sb.Len() 27 | for i := 0; i < l; i++ { 28 | sb.WriteRune('=') 29 | } 30 | sb.WriteString("\nEs la forma más eficiente de construir ") 31 | sb.WriteString("cadenas, de manera condicional o iterativa") 32 | sb.WriteString("\nSin embargo, solo se pueden agregar ") 33 | sb.Write([]byte("cadenas o porciones de bytes o runas")) 34 | sb.WriteString("Para añadir otros tipos, primero debes") 35 | sb.WriteString("transformarlos (p. ej. con strconv.Itoa(") 36 | sb.WriteString(strconv.Itoa(1234)) 37 | sb.WriteByte(')') 38 | 39 | fmt.Println(sb.String()) 40 | } 41 | -------------------------------------------------------------------------------- /ejemplos-libro/07-strings/03-comparacion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | const respuestaCorrecta = "go build" 11 | 12 | func main() { 13 | 14 | fmt.Println("Trivial Go") 15 | fmt.Println("==========") 16 | 17 | fmt.Print("Pregunta 1: qué comando se usa para generar un ejecutable? ") 18 | 19 | // paquete bufio: se explicará en capítulo 14 20 | teclado := bufio.NewReader(os.Stdin) 21 | respuesta, _ := teclado.ReadString('\n') 22 | respuesta = strings.Trim(respuesta, " \n") 23 | 24 | // puedes comparar cadenas con == 25 | if respuesta == respuestaCorrecta { 26 | fmt.Println("Ganaste!") 27 | } else { 28 | fmt.Println("Perdiste :(") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ejemplos-libro/08-diccionarios/01-maps.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | jar := make(map[string]string) 7 | jar["jur"] = "jor" 8 | 9 | // definición literal 10 | capitales := map[string]string{ 11 | "Reino Unido": "Londres", 12 | "España": "Madrid", 13 | "Japón": "Tokyo", 14 | "Francia": "París", 15 | } 16 | 17 | fmt.Println("La capital de Francia es", capitales["Francia"]) 18 | capitales["Marruecos"] = "Rabat" 19 | 20 | // iteración 21 | for pais, capital := range capitales { 22 | fmt.Printf("La capital de %s es %s\n", pais, capital) 23 | } 24 | 25 | // comprobar si un valor está en el mapa 26 | pais := "Narnia" 27 | if capital, ok := capitales[pais]; ok { 28 | fmt.Println("La capital de", pais, "es", capital) 29 | } else { 30 | fmt.Println("No he encontrado ninguna capital para", pais) 31 | } 32 | 33 | delete(capitales, "Reino Unido") 34 | } 35 | -------------------------------------------------------------------------------- /ejemplos-libro/08-diccionarios/02-iteracion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | gastos := map[string]int{ 7 | "Hipoteca": 812, 8 | "Comida": 200, 9 | "Internet y telefono": 100, 10 | "Transporte": 80, 11 | "Suministros de la casa": 145, 12 | "Salir": 150, 13 | "Otros": 350, 14 | } 15 | fmt.Println("Tus gastos mensuales") 16 | total := 0 17 | for clave, valor := range gastos { 18 | fmt.Printf(" - %s: %d\n", clave, valor) 19 | total += valor 20 | } 21 | 22 | fmt.Printf("\nTotal mensual: %d\n", total) 23 | 24 | fmt.Println("\nListado de conceptos:\n") 25 | // Iterando solo las claves 26 | for clave := range gastos { 27 | fmt.Println(clave) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ejemplos-libro/08-diccionarios/03-conjuntos.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Los números ganadores de la lotería son:") 10 | numeros := map[int]struct{}{} 11 | for len(numeros) < 6 { 12 | n := rand.Intn(49) + 1 13 | if _, ok := numeros[n]; !ok { 14 | // si el numero está repetido, no se muestra 15 | numeros[n] = struct{}{} 16 | fmt.Println("El", n, "...") 17 | } 18 | } 19 | fmt.Println("Felicidades a los premiados!") 20 | } 21 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/go.mod: -------------------------------------------------------------------------------- 1 | module macias.info/go/ejemplo 2 | 3 | go 1.14 4 | 5 | require github.com/mariomac/analizador v1.0.0 6 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mariomac/analizador v1.0.0 h1:wKvvzC6PMzdR12+o/jXpWDNoeVD5ClTeRRqpENGa6Bs= 2 | github.com/mariomac/analizador v1.0.0/go.mod h1:Mh1Y0qzJcud69uY77Mldl1oI67B8tEYBsjeD7jZJFdI= 3 | github.com/mariomac/sumadormapa v1.0.0 h1:gzHHYLTjbDrOfluNRjAKlaxdXWmvfXR3LpLq5aUFjCI= 4 | github.com/mariomac/sumadormapa v1.0.0/go.mod h1:UVW2GwjdubkTDbD5w3lj2sMCh9I5h9jzHR6p56lM8uk= 5 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/hola/hola.go: -------------------------------------------------------------------------------- 1 | // Package hola implementa maneras de saludar 2 | package hola 3 | 4 | import "fmt" 5 | 6 | // ConNombre retorna un efusivo saludo, dado un nombre 7 | func ConNombre(nombre string) string { 8 | return fmt.Sprintf("¡Hola, %s!", nombre) 9 | } 10 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/mariomac/analizador" 7 | "macias.info/go/ejemplo/hola" 8 | ) 9 | 10 | func main() { 11 | fmt.Print("Cómo te llamas?: ") 12 | var nombre string 13 | fmt.Scanln(&nombre) 14 | fmt.Println(hola.ConNombre(nombre)) 15 | 16 | analizador.PrintEstadistica(nombre) 17 | } 18 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/analizador/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/analizador/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/analizador/analizador.go: -------------------------------------------------------------------------------- 1 | // Package analizador analiza palabras 2 | package analizador 3 | 4 | import ( 5 | "fmt" 6 | 7 | "github.com/mariomac/sumadormapa/sumador" 8 | ) 9 | 10 | const ( 11 | mays = "mayúsculas" 12 | mins = "minusculas" 13 | cons = "consonantes" 14 | vocs = "vocales" 15 | desc = "desconocidos" 16 | ) 17 | 18 | var vocales = map[rune]rune{ 19 | 'a': 'A', 'A': 'A', 'e': 'E', 'E': 'E', 20 | 'i': 'I', 'I': 'I', 'o': 'O', 'O': 'O', 21 | 'U': 'U', 'u': 'U', 22 | 'á': 'A', 'Á': 'A', 'é': 'E', 'É': 'E', 23 | 'í': 'I', 'Í': 'I', 'ó': 'O', 'Ó': 'O', 24 | 'ú': 'U', 'Ú': 'U', 25 | } 26 | 27 | var vocMayus = map[rune]struct{}{ 28 | 'A': {}, 'E': {}, 'I': {}, 'O': {}, 'U': {}, 29 | 'Á': {}, 'É': {}, 'Í': {}, 'Ó': {}, 'Ú': {}, 30 | } 31 | 32 | // Estadisticas de una palabra 33 | func PrintEstadistica(palabra string) { 34 | sumas := calcula(palabra) 35 | fmt.Printf("La palabra %q contiene:\n", palabra) 36 | fmt.Printf("\t - %d mayúsculas\n", sumas[mays]) 37 | fmt.Printf("\t - %d minúsculas\n", sumas[mins]) 38 | fmt.Printf("\t - %d vocales\n", sumas[vocs]) 39 | fmt.Printf("\t - %d consonantes\n", sumas[cons]) 40 | if cd, ok := sumas[desc] ; ok && cd > 0 { 41 | fmt.Printf("\t - %d carácteres desconocidos\n", sumas[desc]) 42 | } 43 | fmt.Println("Histograma de letras:") 44 | for c := 'A' ; c <= 'Z' ; c++ { 45 | if n, ok := sumas[string(c)] ; ok { 46 | fmt.Printf("\t%c : %d apariciones\n", c, n) 47 | } 48 | } 49 | } 50 | 51 | func calcula(palabra string) sumador.Claves { 52 | sumas := sumador.Claves{} 53 | for _, l := range palabra { 54 | if voc, ok := vocales[l]; ok { 55 | sumas.Incrementa(vocs) 56 | sumas.Incrementa(string(voc)) 57 | if _, ok := vocMayus[l] ; ok { 58 | sumas.Incrementa(mays) 59 | } else { 60 | sumas.Incrementa(mins) 61 | } 62 | } else if l >= 'a' && l <= 'z' { 63 | sumas.Incrementa(mins) 64 | sumas.Incrementa(cons) 65 | sumas.Incrementa(string(l - 'a' + 'A')) 66 | } else if (l >= 'A' && l <= 'Z') || l == 'Ñ' { 67 | sumas.Incrementa(mays) 68 | sumas.Incrementa(cons) 69 | sumas.Incrementa(string(l)) 70 | } else if l == 'ñ' { 71 | sumas.Incrementa(mins) 72 | sumas.Incrementa(cons) 73 | sumas.Incrementa("Ñ") 74 | } else { 75 | sumas.Incrementa(desc) 76 | } 77 | } 78 | return sumas 79 | } 80 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/analizador/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mariomac/analizador 2 | 3 | go 1.14 4 | 5 | require github.com/mariomac/sumadormapa v1.0.0 6 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/analizador/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mariomac/sumadormapa v1.0.0 h1:gzHHYLTjbDrOfluNRjAKlaxdXWmvfXR3LpLq5aUFjCI= 2 | github.com/mariomac/sumadormapa v1.0.0/go.mod h1:UVW2GwjdubkTDbD5w3lj2sMCh9I5h9jzHR6p56lM8uk= 3 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/sumadormapa/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/github.com/mariomac/sumadormapa/sumador/suma.go: -------------------------------------------------------------------------------- 1 | // Package sumador es un ejemplo sin utilidad ninguna 2 | package sumador 3 | 4 | // Claves es un mapa que puede ir añadiendo números según una clave 5 | type Claves map[string]int 6 | 7 | // Incrementa la aparición de una clave concreta. La crea si no existe 8 | func (c Claves) Incrementa(clave string) { 9 | valor, ok := c[clave] 10 | if ok { 11 | valor++ 12 | } else { 13 | valor = 1 14 | } 15 | c[clave] = valor 16 | } 17 | -------------------------------------------------------------------------------- /ejemplos-libro/09-organizacion-codigo/vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/mariomac/analizador v1.0.0 2 | ## explicit 3 | github.com/mariomac/analizador 4 | # github.com/mariomac/sumadormapa v1.0.0 5 | github.com/mariomac/sumadormapa/sumador 6 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/01-definicion tipos.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Año int 6 | type Nacimientos []Año 7 | 8 | type NombreNacimientos map[string]Año 9 | 10 | func main() { 11 | censo := Nacimientos{1979, 1983, 1965} 12 | censo = append(censo, 1990) 13 | censo = append(censo, 1955) 14 | 15 | suma := Año(0) 16 | for _, a := range censo { 17 | suma += a 18 | } 19 | 20 | media := suma / Año(len(censo)) 21 | fmt.Println("Año de nacimiento medio:", media) 22 | 23 | // Same for instantiating MontlyAvgTemp 24 | artistas := NombreNacimientos{ 25 | "Vincent Van Gogh": 1853, 26 | "Elvis Presley": 1935, 27 | "Salvador Dali": 1904, 28 | } 29 | artistas["Rick Astley"] = 1966 30 | for nombre, año := range artistas { 31 | fmt.Printf("%s nació en %d\n", nombre, año) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/02-tipos-funcionales.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | type Generador func() int 9 | 10 | func GenerarTodo(gens ...Generador) []int { 11 | nums := make([]int, 0, len(gens)) 12 | for _, g := range gens { 13 | nums = append(nums, g()) 14 | } 15 | return nums 16 | } 17 | 18 | func Cero() int { 19 | return 0 20 | } 21 | 22 | func Incremento() Generador { 23 | cuenta := 0 24 | return func() int { 25 | cuenta++ 26 | return cuenta 27 | } 28 | } 29 | 30 | func Aleatorio(semilla int64) Generador { 31 | rnd := rand.NewSource(semilla) 32 | return func() int { 33 | return int(rnd.Int63()) 34 | } 35 | } 36 | 37 | func main() { 38 | cnt := Incremento() 39 | rnd := Aleatorio(456) 40 | for i := 0; i < 5; i++ { 41 | fmt.Println(GenerarTodo(Cero, cnt, rnd)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/03-receptores-funcion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type PH float32 8 | 9 | func (p PH) Categoria() string { 10 | switch { 11 | case p < 7: 12 | return "ácido" 13 | case p > 7: 14 | return "básico" 15 | default: 16 | return "neutro" 17 | } 18 | } 19 | 20 | func main() { 21 | phs := []PH{PH(7), PH(1.2), PH(9)} 22 | 23 | for _, ph := range phs { 24 | fmt.Printf("Un pH == %v es %v\n", ph, ph.Categoria()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/04-contador-metodos.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Contador int 6 | 7 | func (c *Contador) Incrementa() { 8 | *c++ 9 | } 10 | 11 | func (c *Contador) Reinicia(nuevoValor int) { 12 | *c = Contador(nuevoValor) 13 | } 14 | 15 | func main() { 16 | var c Contador 17 | c.Incrementa() 18 | c.Incrementa() 19 | c.Incrementa() 20 | fmt.Println("valor:", c) 21 | c.Reinicia(77) 22 | fmt.Println("tras reinicio:", c) 23 | } 24 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/05-pseudo-enumerados.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type PaloBaraja int 9 | 10 | // iota always start as 0 11 | const ( 12 | Copas PaloBaraja = iota 13 | Oros 14 | Bastos 15 | Espadas 16 | ) 17 | 18 | type Card struct { 19 | Number int 20 | Suit PaloBaraja 21 | } 22 | 23 | func (f PaloBaraja) String() string { 24 | switch f { 25 | case Copas: 26 | return "Copas" 27 | case Oros: 28 | return "Oros" 29 | case Bastos: 30 | return "Bastos" 31 | case Espadas: 32 | return "Espadas" 33 | } 34 | return "desconocido" 35 | } 36 | 37 | type Mes int 38 | 39 | // Iota se reinicia en cada grupo de constantes 40 | // Si quieres que los enumerados empiecen en 1, solo añade 41 | // 1 a iota 42 | const ( 43 | Enero Mes = iota + 1 44 | Febrero 45 | Marzo 46 | Abril 47 | Mayo 48 | Junio 49 | Julio 50 | Agosto 51 | Septiembre 52 | Octubre 53 | Noviembre 54 | Diciembre 55 | ) 56 | 57 | type Flag int 58 | 59 | // Puedes usar Iota en cualquier expresión 60 | const ( 61 | Importante Flag = 1 << iota 62 | Urgente 63 | Favorito 64 | TieneAdjunto 65 | ) 66 | 67 | func (f Flag) String() string { 68 | sb := strings.Builder{} 69 | sb.WriteString("Indicadores: ") 70 | if f&Importante != 0 { 71 | sb.WriteString("importante ") 72 | } 73 | if f&Urgente != 0 { 74 | sb.WriteString("urgente ") 75 | } 76 | if f&Favorito != 0 { 77 | sb.WriteString("favorito ") 78 | } 79 | if f&TieneAdjunto != 0 { 80 | sb.WriteString("tieneAdjunto ") 81 | } 82 | return sb.String() 83 | } 84 | 85 | func main() { 86 | 87 | fmt.Println("Mi palo de la baraja favorito es", Oros) 88 | fmt.Println("Enero es el mes número", Enero) 89 | email := Importante | TieneAdjunto 90 | fmt.Println("Recibiste un email:", email) 91 | 92 | // sin embargo, nada te impide crear valores fuera de 93 | // los pseudo-enumerados 94 | v := PaloBaraja(30) 95 | fmt.Println("tengo una carta del palo:", v) 96 | } 97 | -------------------------------------------------------------------------------- /ejemplos-libro/10-tipos/06-duration.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | d := 67 * time.Second 10 | 11 | fmt.Println(d, "es equivalente a", d.Milliseconds(), "milisegundos") 12 | } 13 | -------------------------------------------------------------------------------- /ejemplos-libro/11-tipos-estructurados/01-estructuras-y-metodos.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Cuboide struct { 8 | Ancho float64 9 | Alto float64 10 | Profundo float64 11 | } 12 | 13 | func (c Cuboide) Volumen() float64 { 14 | return c.Ancho * c.Profundo * c.Alto 15 | } 16 | 17 | func (c *Cuboide) Redimensiona(an, al, pr float64) { 18 | c.Ancho = an 19 | c.Alto = al 20 | c.Profundo = pr 21 | } 22 | 23 | func (c Cuboide) String() string { 24 | return fmt.Sprintf("%v x %v x %v", 25 | c.Ancho, c.Profundo, c.Alto) 26 | } 27 | 28 | func main() { 29 | c := Cuboide{Ancho: 2, Profundo: 3, Alto: 2} 30 | fmt.Printf("cuboide %v. volumen %v\n", c, c.Volumen()) 31 | c.Redimensiona(1, 2, 3) 32 | fmt.Printf("cuboide %v. volumen %v\n", c, c.Volumen()) 33 | 34 | fmt.Printf("%#v\n", c) 35 | fmt.Println(c) 36 | } 37 | -------------------------------------------------------------------------------- /ejemplos-libro/11-tipos-estructurados/02-incrustando-structs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Aparato struct { 6 | Nombre string 7 | Precio int 8 | } 9 | 10 | func (g *Aparato) AplicaDescuento(d float32) { 11 | g.Precio = int(float32(g.Precio) * (1 - d)) 12 | } 13 | 14 | type Telefono struct { 15 | Aparato 16 | Pulgadas int 17 | Bateria int 18 | } 19 | 20 | func main() { 21 | s := Telefono{ 22 | Aparato: Aparato{ 23 | Nombre: "Zoomsunk 6G", 24 | Precio: 800, 25 | }, 26 | Pulgadas: 6, 27 | Bateria: 2400, 28 | } 29 | s.AplicaDescuento(0.15) 30 | fmt.Printf("telefono con descuento %+v\n", s) 31 | } 32 | -------------------------------------------------------------------------------- /ejemplos-libro/11-tipos-estructurados/03-estructura-vacia.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | duplicados := []string{ 7 | "Juan", "María", "Benito", "Juan", "Carlos", "Mario", 8 | "Benito", "Carlos", "María", "Juan", "Cristina", 9 | "Isabel", "Carlos", "Juan", "Belinda", 10 | } 11 | 12 | unicos := map[string]struct{}{} 13 | 14 | for _, nombre := range duplicados { 15 | unicos[nombre] = struct{}{} 16 | } 17 | 18 | fmt.Println("La lista de nombres únicos es: ") 19 | for nombre := range unicos { // remember we can interate only the keys 20 | fmt.Println(" -", nombre) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ejemplos-libro/11-tipos-estructurados/04-opciones-funcionales.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Estudiante struct { 8 | nombre string 9 | nacimiento time.Time 10 | descuento bool 11 | } 12 | 13 | type Opcion func(*Estudiante) 14 | 15 | func Nombre(nombre string) Opcion { 16 | return func(stud *Estudiante) { 17 | stud.nombre = nombre 18 | } 19 | } 20 | 21 | func Nacimiento(nacimiento time.Time) Opcion { 22 | return func(stud *Estudiante) { 23 | stud.nacimiento = nacimiento 24 | } 25 | } 26 | 27 | func Descuento() Opcion { 28 | return func(stud *Estudiante) { 29 | stud.descuento = true 30 | } 31 | } 32 | 33 | func NewEstudiante(opciones ...Opcion) Estudiante { 34 | stud := Estudiante{ 35 | nombre: "desconocido", 36 | } 37 | for _, opt := range opciones { 38 | opt(&stud) 39 | } 40 | return stud 41 | } 42 | 43 | func main() { 44 | estu1 := NewEstudiante() 45 | estu2 := NewEstudiante(Nombre("Pedro"), Descuento()) 46 | estu3 := NewEstudiante(Nombre("Juan"), Nacimiento( 47 | time.Date(2001, 10, 12, 0, 0, 0, 0, time.UTC))) 48 | 49 | // evitamos error de compilación por no usar las 50 | // variables generadas como ejemplo 51 | _, _, _ = estu1, estu2, estu3 52 | } 53 | -------------------------------------------------------------------------------- /ejemplos-libro/12-interfaces/01-uso-basico.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Saludador interface { 6 | Saluda() string 7 | } 8 | 9 | type Perro struct { 10 | Nombre string 11 | } 12 | 13 | func (d Perro) Saluda() string { 14 | return "Guau!!" 15 | } 16 | 17 | // Implementación implícita de la interfaz fmt.Stringer 18 | func (d *Perro) String() string { 19 | return "Un perro llamado " + d.Nombre 20 | } 21 | 22 | func main() { 23 | var saludador Saludador = Perro{Nombre: "Bingo"} 24 | var str fmt.Stringer = &Perro{Nombre: "Rufo"} 25 | 26 | fmt.Println(saludador.Saluda()) 27 | fmt.Println(str.String()) 28 | } 29 | -------------------------------------------------------------------------------- /ejemplos-libro/12-interfaces/02-casting-seguro.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Perro struct{} 8 | 9 | func (p *Perro) Ladra() string { 10 | return "¡Guau!" 11 | } 12 | 13 | type Rana struct{} 14 | 15 | func (r *Rana) Croa() string { 16 | return "¡Croac!" 17 | } 18 | 19 | type Canguro struct{} 20 | 21 | func (c *Canguro) Salta() string { 22 | return "¡Boing!" 23 | } 24 | 25 | func main() { 26 | animales := []interface{}{ 27 | 123, Canguro{}, "un gato", Perro{}, Rana{}, 28 | } 29 | 30 | for _, a := range animales { 31 | fmt.Printf("%#v", a) 32 | if p, ok := a.(Perro); ok { 33 | fmt.Print(": ", p.Ladra()) 34 | } 35 | if r, ok := a.(Rana); ok { 36 | fmt.Print(": ", r.Croa()) 37 | } 38 | if c, ok := a.(Canguro); ok { 39 | fmt.Print(": ", c.Salta()) 40 | } 41 | fmt.Println() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ejemplos-libro/12-interfaces/03-analisis-de-patrones.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Perro struct{} 8 | 9 | func (p *Perro) Ladra() string { 10 | return "¡Guau!" 11 | } 12 | 13 | type Rana struct{} 14 | 15 | func (r *Rana) Croa() string { 16 | return "¡Croac!" 17 | } 18 | 19 | type Canguro struct{} 20 | 21 | func (c *Canguro) Salta() string { 22 | return "¡Boing!" 23 | } 24 | 25 | func main() { 26 | animales := []interface{}{ 27 | 123, Canguro{}, "un gato", Perro{}, Rana{}, 28 | } 29 | for _, a := range animales { 30 | switch x := a.(type) { 31 | case Rana: 32 | fmt.Println("Una rana:", x.Croa()) 33 | case Canguro: 34 | fmt.Println("Un canguro:", x.Salta()) 35 | case Perro: 36 | fmt.Println("Un Perro:", x.Ladra()) 37 | default: 38 | fmt.Println("No sé qué es exactamente esto:", x) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ejemplos-libro/12-interfaces/04-tipado-pato.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | type ConversorMilisegundos interface { 9 | Milliseconds() int64 10 | } 11 | 12 | func MuestraMS(c ConversorMilisegundos) { 13 | fmt.Println("esto son", c.Milliseconds(), "milisegundos") 14 | } 15 | 16 | func main() { 17 | // el tipo time.Duration, que ya existe, se amolda a la 18 | // interfaz ConversorMilisegundos, recién creada 19 | MuestraMS(23 * time.Second) 20 | } 21 | -------------------------------------------------------------------------------- /ejemplos-libro/12-interfaces/05-interfaz-vacia.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Nombre struct { 6 | DePila string 7 | Apellido string 8 | } 9 | 10 | func main() { 11 | var cualquierCosa interface{} 12 | 13 | cualquierCosa = 1 14 | cualquierCosa = true 15 | cualquierCosa = "hello" 16 | cualquierCosa = Nombre{DePila: "Alan", Apellido: "Turing"} 17 | 18 | fmt.Println(cualquierCosa) 19 | } 20 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/01-errors-new.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func divide(dividend, divisor int) (int, error) { 9 | if divisor == 0 { 10 | return 0, errors.New("no puedo dividir por cero") 11 | } 12 | return dividend / divisor, nil 13 | } 14 | 15 | func main() { 16 | div, err := divide(7, 0) 17 | if err != nil { 18 | fmt.Println("error!", err) 19 | return 20 | } 21 | fmt.Println("resultado: ", div) 22 | } 23 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/02-fmt-errorf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func raizCuadrada(num float64) (float64, error) { 9 | if num < 0 { 10 | return 0, fmt.Errorf("%f no tiene raiz cuadrada real", num) 11 | } 12 | return math.Sqrt(num), nil 13 | } 14 | 15 | func main() { 16 | res, err := raizCuadrada(-3) 17 | if err != nil { 18 | fmt.Println("error!", err) 19 | return 20 | } 21 | fmt.Println("resultado: ", res) 22 | } 23 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/03-errores-centinela.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | ErrYaExiste = errors.New("clave ya existe") 10 | ErrNoCapacidad = errors.New("no hay capacidad") 11 | ErrClaveInvalida = errors.New("clave inválida") 12 | ) 13 | 14 | type Almacen struct { 15 | capacidad int 16 | elementos map[string]interface{} 17 | } 18 | 19 | func NewAlmacen(capacidad int) Almacen { 20 | return Almacen{ 21 | capacidad: capacidad, 22 | elementos: map[string]interface{}{}, 23 | } 24 | } 25 | 26 | func (s *Almacen) Guarda( 27 | clave string, valor interface{}) error { 28 | 29 | // verifica que la clave sea legal 30 | if clave == "" { 31 | return ErrClaveInvalida 32 | } 33 | // verifica que no se haya llegado al límite de elementos 34 | if len(s.elementos) >= s.capacidad { 35 | return ErrNoCapacidad 36 | } 37 | // verifica que la clave no exista ya 38 | if _, ok := s.elementos[clave]; ok { 39 | return ErrYaExiste 40 | } 41 | // todo OK: guardar el valor 42 | s.elementos[clave] = valor 43 | return nil 44 | } 45 | 46 | func main() { 47 | s := NewAlmacen(30) 48 | err := s.Guarda("un_numero", 12345) 49 | switch err { 50 | case ErrYaExiste: 51 | fmt.Println(err, ": prueba con otra clave única") 52 | case ErrNoCapacidad: 53 | fmt.Println(err, ": no se pueden guardar más elementos") 54 | case ErrClaveInvalida: 55 | fmt.Println(err, ": prueba con otra clave bien formateada") 56 | case nil: 57 | fmt.Println("operación llevada a cabo con éxito!") 58 | default: 59 | fmt.Println("error desconocido:", err) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/04-implementaciones-error.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Comida string 6 | 7 | const ( 8 | ComidaPerro = Comida("Comida de perro") 9 | ComidaHumano = Comida("Comida humana") 10 | ComidaGato = Comida("Comida de gato") 11 | ComidaPajaro = Comida("Comida de pájaro") 12 | ) 13 | 14 | type NoHambre struct{} 15 | 16 | func (n NoHambre) Error() string { 17 | return "el perro no tiene hambre" 18 | } 19 | 20 | type NoApetecible struct { 21 | Ofrecido Comida 22 | } 23 | 24 | func (d NoApetecible) Error() string { 25 | return "a los perros no les gusta " + string(d.Ofrecido) 26 | } 27 | 28 | type Perro struct { 29 | TieneHambre bool 30 | } 31 | 32 | func (d *Perro) Alimenta(f Comida) error { 33 | if !d.TieneHambre { 34 | return NoHambre{} 35 | } 36 | if f != ComidaPerro && f != ComidaHumano { 37 | return NoApetecible{Ofrecido: f} 38 | } 39 | fmt.Println("comiendo", f, ": ñam ñam ñam!") 40 | d.TieneHambre = false 41 | return nil 42 | } 43 | 44 | func main() { 45 | dog := Perro{TieneHambre: true} 46 | food := []Comida{ 47 | ComidaPajaro, ComidaGato, ComidaPerro, ComidaHumano, 48 | } 49 | for _, f := range food { 50 | err := dog.Alimenta(f) 51 | switch err.(type) { 52 | case NoApetecible: 53 | fmt.Println(err, "-> prueba otro tipo de comida") 54 | case NoHambre: 55 | fmt.Println(err, "-> espera unas horas") 56 | case error: 57 | fmt.Println(err, "(no esperaba esto!)") 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/05-envoltura-errores.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | err := errors.New("boom") 10 | err2 := fmt.Errorf("algo malo sucedió: %w", err) 11 | fmt.Println(err2) 12 | 13 | causa := errors.Unwrap(err2) 14 | fmt.Println("la causa es", causa) 15 | causa = errors.Unwrap(causa) 16 | fmt.Println("la causa de la causa es", causa) 17 | } 18 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/06-envoltura-errores-structs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type ErrorTV struct { 9 | Causa error 10 | } 11 | 12 | func (e ErrorTV) Error() string { 13 | return fmt.Sprint("problema con la TV:", e.Causa) 14 | } 15 | 16 | func (e ErrorTV) Unwrap() error { 17 | return e.Causa 18 | } 19 | 20 | type ErrorComponente struct { 21 | Nombre string 22 | } 23 | 24 | func (e ErrorComponente) Error() string { 25 | return "fallo de un componente:" + e.Nombre 26 | } 27 | 28 | func main() { 29 | err := ErrorTV{ 30 | Causa: ErrorComponente{Nombre: "Condensador"}, 31 | } 32 | var errTV ErrorTV 33 | if errors.As(err, &errTV) { 34 | fmt.Println("encontrado en cadena de error:", errTV) 35 | } 36 | var errComp ErrorComponente 37 | if errors.As(err, &errComp) { 38 | fmt.Println("encontrado en cadena de error:", errComp) 39 | } 40 | err = ErrorTV{ 41 | Causa: errors.New("la TV explotó"), 42 | } 43 | if errors.As(err, &errComp) { 44 | fmt.Println("Esto nunca debería mostrarse") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/07-panics.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func muestra(cadena *string) { 6 | fmt.Println(*cadena) 7 | panic("ha sucedido algo realmente malo") 8 | } 9 | 10 | func main() { 11 | muestra(nil) 12 | 13 | fmt.Println("este mensaje no se mostrará") 14 | 15 | p := recover() 16 | fmt.Println("recovering from panic: ", p) 17 | } 18 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/08-defer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("hola") 7 | defer fmt.Println("ejecución aplazada") 8 | fmt.Println("adiós!") 9 | } 10 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/09-panic-recover.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func funcion1() { 6 | defer func() { 7 | if p := recover(); p != nil { 8 | fmt.Println("recuperándonos del pánico:", p) 9 | } 10 | }() 11 | funcion2() 12 | fmt.Println("texto no mostrado") 13 | } 14 | 15 | func funcion2() { 16 | panic("ha sucedido algo realmente malo") 17 | } 18 | 19 | func main() { 20 | fmt.Println("invocando una función") 21 | funcion1() 22 | fmt.Println("saliendo con normalidad") 23 | } 24 | -------------------------------------------------------------------------------- /ejemplos-libro/13-errores/10-panic-implicito.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func add(n int, np *int) int { 6 | // si np == nil, lanzará pánico 7 | return n + *np 8 | } 9 | 10 | func main() { 11 | defer func() { 12 | if r := recover() ; r != nil { 13 | fmt.Println("Recuperándonos de pánico:", r) 14 | } 15 | }() 16 | var nilRef *int = nil 17 | fmt.Println("*nilRef + 3: ", add(3, nilRef)) 18 | 19 | fmt.Println("Esto no se mostrará") 20 | } 21 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/010-writers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | n, err := os.Stdout.Write([]byte("hola!\n")) 10 | if err != nil { 11 | fmt.Println("Error:", err) 12 | return 13 | } 14 | fmt.Println("escritos", n, "bytes") 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/020-readers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | func printRead(r io.Reader) { 10 | slice := make([]byte, 10) // read reads until len(slice), NOT until cap(slice) 11 | 12 | num, err := r.Read(slice) 13 | if err != nil { 14 | fmt.Println("Reading error! ", err.Error()) 15 | return 16 | } 17 | fmt.Println("I read:", string(slice[:num])) 18 | } 19 | 20 | func main() { 21 | fmt.Print("Escribe 10 carácteres: ") 22 | datos := make([]byte, 10) // read reads until len(slice), NOT until cap(slice) 23 | n, err := os.Stdin.Read(datos) 24 | if err != nil { 25 | fmt.Println("error leyendo:", err) 26 | return 27 | } 28 | fmt.Println("leídos", n, "bytes:", string(datos)) 29 | } 30 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/030-files.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Escribiendo archivo...") 10 | fichero, err := os.Create("ejemplo.txt") 11 | if err != nil { 12 | fmt.Println(err) 13 | os.Exit(-1) 14 | } 15 | 16 | if _, err = fichero.Write([]byte("hola!")); err != nil { 17 | fmt.Println(err) 18 | os.Exit(-1) 19 | } 20 | fichero.Close() // interface Closer 21 | 22 | fmt.Println("Leyendo archivo... ") 23 | if fichero, err = os.Open("ejemplo.txt"); err != nil { 24 | fmt.Println(err) 25 | os.Exit(-1) 26 | } 27 | defer fichero.Close() 28 | leido := make([]byte, 256) 29 | n, err := fichero.Read(leido) 30 | if err != nil { 31 | fmt.Println(err) 32 | os.Exit(-1) 33 | } 34 | fmt.Printf("leídos %v bytes: %s\n", n, string(leido[:n])) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/035-fprint-fscan.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | fichero, _ := os.Create("ejemplo.txt") 10 | 11 | n, _ := fmt.Fprintf(fichero, "Hola %v!\n", 1234) 12 | fichero.Close() 13 | fmt.Printf("escritos %v bytes\n", n) 14 | 15 | fichero, _ = os.Open("ejemplo.txt") 16 | 17 | var num int 18 | n, _ = fmt.Fscanf(fichero, "Hola %d", &num) 19 | fmt.Printf("leído %v argumento: %v\n", n, num) 20 | fichero.Close() 21 | } 22 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/040-bufio.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | func main() { 11 | buff := bytes.NewBufferString(`hola que tal 12 | probando texto 13 | multilínea`) 14 | 15 | sc := bufio.NewReader(buff) 16 | 17 | leido, err := sc.ReadString('\n') 18 | for err == nil { 19 | fmt.Print("leida línea:", leido) 20 | leido, err = sc.ReadString('\n') 21 | } 22 | 23 | if err == io.EOF { 24 | fmt.Println("línea final:", leido) 25 | } else { 26 | fmt.Println("error inesperado:", err.Error()) 27 | return 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/045-scanner.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | buff := bytes.NewBufferString(`hola que tal 11 | probando escaneo 12 | multilínea`) 13 | 14 | sc := bufio.NewScanner(buff) 15 | sc.Split(bufio.ScanLines) 16 | linea := 1 17 | for sc.Scan() { 18 | fmt.Printf("%d: %s\n", linea, sc.Text()) 19 | linea++ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/050-ioutil.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | ) 9 | 10 | func main() { 11 | tmpDir, err := ioutil.TempDir("", "ioutil") 12 | exitIfErr(err) 13 | 14 | fileName := path.Join(tmpDir, "ioutil.txt") 15 | 16 | err = ioutil.WriteFile(fileName, []byte("algo de texto\naqui"), 0644) 17 | exitIfErr(err) 18 | 19 | contents, err := ioutil.ReadFile(fileName) 20 | exitIfErr(err) 21 | 22 | fmt.Println("leido desde ", fileName, ":") 23 | fmt.Println(string(contents)) 24 | } 25 | 26 | func exitIfErr(err error) { 27 | if err != nil { 28 | fmt.Println("Fallo: ", err.Error()) 29 | os.Exit(-1) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/060-log.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "log" 4 | 5 | func main() { 6 | log.Println("Empezando el programa") 7 | for i := 1; i <= 3; i++ { 8 | log.Printf("Mostrando evento %d\n", i) 9 | } 10 | log.Println("Saliendo del programa") 11 | } 12 | -------------------------------------------------------------------------------- /ejemplos-libro/14-entrada-salida/080-reader-writer-en-buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | buff := bytes.Buffer{} 10 | buff.WriteString("hello\n") 11 | str, _ := buff.ReadString('\n') // ignorando el error, por simplicidad 12 | fmt.Println("leido:", str) 13 | 14 | fmt.Fprintf(&buff, "donuts %.02f\n", 12.0) 15 | 16 | var clave string 17 | var valor float32 18 | fmt.Fscanf(&buff, "%s %f", &clave, &valor) 19 | fmt.Printf("clave: %v. valor: %v\n", clave, valor) 20 | 21 | } 22 | -------------------------------------------------------------------------------- /ejemplos-libro/15-paralelismo-concurrencia/01-gorrutinas.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func cincoVeces(msg string) { 6 | for i := 1; i <= 5; i++ { 7 | fmt.Printf("(%d de 5) %s\n", i, msg) 8 | } 9 | } 10 | 11 | func main() { 12 | fmt.Println("Lanzando gorutina") 13 | 14 | go cincoVeces("Esta gorutina no siempre se completará") 15 | cincoVeces("Este mensaje se mostrará exactamente 5 veces") 16 | 17 | fmt.Println("Finalizando programa") 18 | } 19 | -------------------------------------------------------------------------------- /ejemplos-libro/15-paralelismo-concurrencia/02-sync-waitgroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func main() { 9 | const numTareas = 3 10 | 11 | wg := sync.WaitGroup{} 12 | wg.Add(numTareas) 13 | 14 | for i := 0 ; i < numTareas; i++ { 15 | // "i" está compartida por todas las gorrutinas, así que 16 | // la copiamos en una variable de ámbito exclusivo para cada 17 | // gorrutina 18 | numTarea := i 19 | go func() { 20 | defer wg.Done() 21 | // no se garantiza el orden de completado 22 | fmt.Println("Ejecutando tarea", numTarea) 23 | }() 24 | } 25 | 26 | wg.Wait() 27 | fmt.Println("Completadas todas las tareas. Finalizando") 28 | } -------------------------------------------------------------------------------- /ejemplos-libro/15-paralelismo-concurrencia/03-motivacion-mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync" 7 | ) 8 | 9 | // Suma todos los elementos 10 | func Suma(porcion []int) int { 11 | total := 0 12 | for _, n := range porcion { 13 | total += n 14 | } 15 | return total 16 | } 17 | 18 | func main() { 19 | tareasParalelas := runtime.GOMAXPROCS(0) 20 | 21 | v := []int{0, 1, 3, 1, 0, 7, 8, 9, 3, 3, 0, 2} 22 | 23 | // experimento: lo repetimos indefinidamente, y el panic 24 | // final acabará lanzándose por causa de una condición de carrera 25 | for true { 26 | wg := sync.WaitGroup{} 27 | wg.Add(tareasParalelas) 28 | 29 | totalSuma := 0 30 | for t := 0; t < tareasParalelas; t++ { 31 | s := t 32 | go func() { 33 | defer wg.Done() 34 | inicio := s * len(v) / tareasParalelas 35 | fin := (s + 1) * len(v) / tareasParalelas 36 | suma := Suma(v[inicio:fin]) 37 | totalSuma += suma 38 | }() 39 | } 40 | 41 | wg.Wait() 42 | if totalSuma != 37 { 43 | panic(fmt.Sprint("totalSuma: ", totalSuma)) 44 | } 45 | } 46 | //fmt.Println("total sum: ", totalSuma) 47 | } 48 | -------------------------------------------------------------------------------- /ejemplos-libro/15-paralelismo-concurrencia/04-mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync" 7 | ) 8 | 9 | func Suma(porcion []int) int { 10 | total := 0 11 | for _, n := range porcion { 12 | total += n 13 | } 14 | return total 15 | } 16 | 17 | func main() { 18 | tareasParalelas := runtime.GOMAXPROCS(0) 19 | 20 | v := []int{0, 1, 3, 1, 0, 7, 8, 9, 3, 3, 0, 2} 21 | 22 | // experimento: el programa nunca lanzará panic, porqu el 23 | // acceso concurrente a totalSuma ahora está bien sincronizado 24 | // mediante un mutex 25 | for true { 26 | mt := sync.Mutex{} 27 | wg := sync.WaitGroup{} 28 | wg.Add(tareasParalelas) 29 | 30 | totalSuma := 0 31 | for t := 0; t < tareasParalelas; t++ { 32 | s := t 33 | go func() { 34 | defer wg.Done() 35 | inicio := s * len(v) / tareasParalelas 36 | fin := (s + 1) * len(v) / tareasParalelas 37 | suma := Suma(v[inicio:fin]) 38 | 39 | mt.Lock() 40 | totalSuma += suma 41 | mt.Unlock() 42 | }() 43 | } 44 | 45 | wg.Wait() 46 | if totalSuma != 37 { 47 | panic(fmt.Sprint("totalSuma: ", totalSuma)) 48 | } 49 | } 50 | //fmt.Println("total sum: ", totalSuma) 51 | } 52 | -------------------------------------------------------------------------------- /ejemplos-libro/15-paralelismo-concurrencia/05-atomic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync" 7 | "sync/atomic" 8 | ) 9 | 10 | func Suma(porcion []int) int { 11 | total := 0 12 | for _, n := range porcion { 13 | total += n 14 | } 15 | return total 16 | } 17 | 18 | func main() { 19 | tareasParalelas := runtime.GOMAXPROCS(0) 20 | 21 | v := []int{0, 1, 3, 1, 0, 7, 8, 9, 3, 3, 0, 2} 22 | 23 | // experimento: el panic nunca se lanzará porque el acceso 24 | // a totalSuma está sincronizado mediante operaciones atómicas 25 | for true { 26 | wg := sync.WaitGroup{} 27 | wg.Add(tareasParalelas) 28 | 29 | totalSuma := int64(0) 30 | for t := 0; t < tareasParalelas; t++ { 31 | s := t 32 | go func() { 33 | defer wg.Done() 34 | inicio := s * len(v) / tareasParalelas 35 | fin := (s + 1) * len(v) / tareasParalelas 36 | suma := Suma(v[inicio:fin]) 37 | 38 | atomic.AddInt64(&totalSuma, int64(suma)) 39 | }() 40 | } 41 | 42 | wg.Wait() 43 | if totalSuma != 37 { 44 | panic(fmt.Sprint("totalSuma: ", totalSuma)) 45 | } 46 | } 47 | //fmt.Println("total sum: ", totalSuma) 48 | } 49 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/01-envio-basico.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan string) 7 | 8 | go func() { 9 | ch <- "Hola" 10 | }() 11 | 12 | recibido := <-ch 13 | fmt.Println("He recibido:", recibido) 14 | // no es necesario cerrar channel 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/02-bloqueo-deadlock.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan string, 5) 7 | ch <- "hola" 8 | recibido := <-ch 9 | fmt.Println(recibido) 10 | } 11 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/03-panic-cerrado.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan string) 7 | close(ch) 8 | 9 | x := <-ch 10 | fmt.Println("x:", x) 11 | 12 | ch <- "hooola" 13 | } 14 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/04-sin-buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const nums = 3 6 | 7 | func Emisor(ch chan<- int) { 8 | for i := 1; i <= nums; i++ { 9 | ch <- i 10 | fmt.Println(i, "enviado correctamente") 11 | } 12 | } 13 | 14 | func Receptor(ch <-chan int) { 15 | for i := 1; i <= nums; i++ { 16 | num := <-ch 17 | fmt.Println("recibido:", num) 18 | } 19 | } 20 | 21 | func main() { 22 | ch := make(chan int) 23 | 24 | go Emisor(ch) 25 | Receptor(ch) 26 | } 27 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/05-con-buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Emisor(ch chan<- int) { 6 | for i := 1; i <= 3; i++ { 7 | ch <- i 8 | fmt.Println(i, "enviado correctamente") 9 | } 10 | } 11 | 12 | func Receptor(ch <-chan int) { 13 | for { 14 | num := <-ch 15 | fmt.Println("recibido:", num) 16 | } 17 | } 18 | 19 | func main() { 20 | ch := make(chan int, 10) 21 | 22 | go Receptor(ch) 23 | Emisor(ch) 24 | } 25 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/06-cerrando-con-buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan int, 3) 7 | ch <- 1 8 | ch <- 2 9 | ch <- 3 10 | close(ch) 11 | 12 | for num := range ch { 13 | fmt.Println("Recibiendo:", num) 14 | } 15 | fmt.Println("Canal cerrado. Fin!") 16 | } 17 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/07-sincronizacion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func TareaAsincrona() <-chan struct{} { 6 | ch := make(chan struct{}) 7 | go func() { 8 | fmt.Println("haciendo alguna cosa en paralelo...") 9 | for i := 0; i < 3; i++ { 10 | fmt.Println(i, "...") 11 | } 12 | fmt.Println("finalizada tarea en paralelo") 13 | 14 | close(ch) 15 | }() 16 | return ch 17 | } 18 | 19 | func main() { 20 | 21 | espera := TareaAsincrona() 22 | 23 | <-espera 24 | 25 | fmt.Println("programa finalizado") 26 | } 27 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/08-multiples-receptores.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func Engullidor(nombre string, dulces <-chan string) { 9 | for { 10 | dulce := <-dulces 11 | fmt.Println(nombre, "come", dulce) 12 | } 13 | } 14 | 15 | func main() { 16 | dulces := make(chan string, 10) 17 | 18 | go Engullidor("Marcos", dulces) 19 | go Engullidor("Aina", dulces) 20 | go Engullidor("Judit", dulces) 21 | 22 | dulces <- "Donut" 23 | time.Sleep(time.Second) 24 | dulces <- "Crusán" 25 | time.Sleep(time.Second) 26 | dulces <- "Ensaimada" 27 | time.Sleep(time.Second) 28 | 29 | time.Sleep(2 * time.Second) 30 | } 31 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/09-iterando-canal.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func Engullidor(nombre string, dulces <-chan string) { 9 | for dulce := range dulces { 10 | fmt.Println(nombre, "come", dulce) 11 | } 12 | fmt.Println(nombre, ": No más dulces? Adiós!") 13 | } 14 | 15 | func main() { 16 | dulces := make(chan string) 17 | wg := sync.WaitGroup{} 18 | wg.Add(3) 19 | 20 | for _, nom := range []string{"Marcos", "Aina", "Judit"} { 21 | n := nom 22 | go func() { 23 | defer wg.Done() 24 | Engullidor(n, dulces) 25 | }() 26 | } 27 | 28 | dulces <- "Donut" 29 | dulces <- "Crusán" 30 | dulces <- "Ensaimada" 31 | dulces <- "Pestiño" 32 | 33 | close(dulces) 34 | 35 | wg.Wait() 36 | fmt.Println("Todos los dulces repartidos y engullidos") 37 | } 38 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/10-select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func CentralMensajeria(sms, email, carta <-chan string) { 9 | for { 10 | select { 11 | case num := <-sms: 12 | fmt.Println("recibido SMS del número", num) 13 | case dir := <-email: 14 | fmt.Println("recibido email de dirección", dir) 15 | case rem := <-carta: 16 | fmt.Println("recibida carta de remitente", rem) 17 | } 18 | } 19 | } 20 | 21 | func main() { 22 | sms := make(chan string) 23 | email := make(chan string) 24 | carta := make(chan string) 25 | 26 | go CentralMensajeria(sms, email, carta) 27 | 28 | // no se garantiza recepción ordenada entre diferentes 29 | // canales (sí dentro de un mismo canal) 30 | sms <- "777889923" 31 | email <- "yahoo@google.com" 32 | carta <- "Banco Central Hispano" 33 | email <- "noreply@example.com" 34 | 35 | time.Sleep(2 * time.Second) 36 | } 37 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/11-timeouts.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | ch := make(chan int) 10 | 11 | go func() { 12 | fmt.Println( 13 | "Calculando la respuesta a la Gran Pregunta" + 14 | "de la Vida, el Universo, y Todo lo Demás") 15 | time.Sleep(15 * time.Second) 16 | ch <- 42 17 | }() 18 | 19 | fmt.Println("Esperando...") 20 | select { 21 | case ret := <-ch: 22 | fmt.Println("Recibido:", ret) 23 | case <-time.After(2 * time.Second): 24 | fmt.Println("Error: tiempo de espera agotado") 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ejemplos-libro/16-canales/12-context-cancel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func MuestraRetardada(ctx context.Context, msg string) { 10 | select { 11 | case <-time.After(5 * time.Second): 12 | fmt.Println(msg) 13 | case <-ctx.Done(): 14 | // proceso interrumpido! La función continúa 15 | } 16 | } 17 | 18 | func main() { 19 | ctx, cancela := context.WithCancel(context.Background()) 20 | fmt.Println("Un mensaje se mostrará en 5 segundos...") 21 | go func() { 22 | fmt.Println("Pulsa INTRO para cancelar mensaje") 23 | fmt.Scanf("\n") 24 | cancela() 25 | }() 26 | 27 | MuestraRetardada(ctx, "Hola!!") 28 | fmt.Println("finalizando") 29 | } 30 | -------------------------------------------------------------------------------- /ejemplos-libro/17-servicios-web/minirest/minirest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | type Rest struct { 10 | entradas map[string]string 11 | } 12 | 13 | func (mr *Rest) ServeHTTP( 14 | rw http.ResponseWriter, req *http.Request) { 15 | 16 | // obtener identificador y documento (si hay alguno) 17 | // de la petición 18 | identificador := req.URL.Path 19 | var documento string 20 | if req.Body != nil { 21 | b, _ := ioutil.ReadAll(req.Body) 22 | documento = string(b) 23 | } 24 | 25 | // las respuestas a retornar no siguen un formato concreto 26 | rw.Header().Add("Content-Type", "text/plain") 27 | 28 | // según el método de la petición, nuestro http.Handler 29 | // llevará a cabo una u otra acción 30 | switch req.Method { 31 | case http.MethodGet: 32 | mr.peticionGet(identificador, rw) 33 | case http.MethodDelete: 34 | mr.peticionDelete(identificador, rw) 35 | case http.MethodPut: 36 | mr.peticionPut(identificador, documento, rw) 37 | case http.MethodPost: 38 | mr.peticionPost(identificador, documento, rw) 39 | default: 40 | rw.WriteHeader(http.StatusBadRequest) 41 | fmt.Fprintln(rw, "inválido:", req.Method) 42 | } 43 | } 44 | 45 | func (mr *Rest) peticionGet( 46 | identificador string, rw http.ResponseWriter) { 47 | 48 | if documento, ok := mr.entradas[identificador]; ok { 49 | fmt.Fprintln(rw, documento) 50 | } else { 51 | rw.WriteHeader(http.StatusNotFound) 52 | fmt.Fprintln(rw, "no encontrado:", identificador) 53 | } 54 | } 55 | 56 | func (mr *Rest) peticionDelete( 57 | identificador string, rw http.ResponseWriter) { 58 | if _, ok := mr.entradas[identificador]; ok { 59 | delete(mr.entradas, identificador) 60 | fmt.Fprintln(rw, "OK") 61 | } else { 62 | rw.WriteHeader(http.StatusNotFound) 63 | fmt.Fprintln(rw, "no encontrado:", identificador) 64 | } 65 | } 66 | 67 | func (mr *Rest) peticionPut( 68 | identificador, documento string, rw http.ResponseWriter) { 69 | 70 | if _, ok := mr.entradas[identificador]; ok { 71 | mr.entradas[identificador] = documento 72 | fmt.Fprintln(rw, "OK") 73 | } else { 74 | rw.WriteHeader(http.StatusNotFound) 75 | fmt.Fprintln(rw, "no encontrado:", identificador) 76 | } 77 | } 78 | 79 | func (mr *Rest) peticionPost( 80 | identificador, documento string, rw http.ResponseWriter) { 81 | 82 | if _, ok := mr.entradas[identificador]; ok { 83 | rw.WriteHeader(http.StatusBadRequest) 84 | fmt.Fprintln(rw, "ya existente:", identificador) 85 | } else { 86 | mr.entradas[identificador] = documento 87 | fmt.Fprintln(rw, "OK") 88 | } 89 | } 90 | 91 | func main() { 92 | capitales := Rest{ 93 | entradas: map[string]string{}, 94 | } 95 | 96 | http.Handle("/", &capitales) 97 | 98 | panic(http.ListenAndServe(":8080", nil)) 99 | } 100 | -------------------------------------------------------------------------------- /ejemplos-libro/17-servicios-web/minirest/minirest_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "net/http" 7 | "net/http/httptest" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Testing: ver capítulo 20 13 | func TestPost(t *testing.T) { 14 | // DADO un servicio REST de guardado de documentos 15 | handler := Rest{entradas: map[string]string{}} 16 | servidor := httptest.NewServer(&handler) 17 | cliente := servidor.Client() 18 | 19 | // CUANDO se inserta un documento 20 | resp, err := cliente.Post( 21 | servidor.URL+"/Japon", 22 | "text/plain", 23 | strings.NewReader("Tokyo"), 24 | ) 25 | if err != nil { 26 | t.Error(err) 27 | } 28 | // ENTONCES el servidor responde 200 OK 29 | if resp.StatusCode != http.StatusOK { 30 | t.Error("Esperaba 200 OK pero obtuve", resp.StatusCode) 31 | } 32 | 33 | // Y CUANDO se busca de nuevo ese documento 34 | resp, err = cliente.Get(servidor.URL + "/Japon") 35 | if err != nil { 36 | t.Error(err) 37 | } 38 | documento, err := ioutil.ReadAll(resp.Body) 39 | if err != nil { 40 | t.Error(err) 41 | } 42 | // ENTONCES el documento retornado es igual 43 | // al documento enviado (quitando el salto de línea 44 | // "\n" que el servidor añade) 45 | documento = bytes.Trim(documento, "\n") 46 | if string(documento) != "Tokyo" { 47 | t.Error("Esperaba Tokyo pero obtuve", string(documento)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ejemplos-libro/17-servicios-web/servidor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | type HolaServicio struct{} 11 | 12 | func (hs *HolaServicio) ServeHTTP( 13 | rw http.ResponseWriter, req *http.Request) { 14 | 15 | rw.Header().Add("Content-Type", "text/html") 16 | 17 | documento := fmt.Sprintf(` 18 |
Ruta de acceso: %s
20 | `, req.URL.Path) 21 | // status code 200 es implícito si no se indica otro 22 | rw.Write([]byte(documento)) 23 | } 24 | 25 | func main() { 26 | go func() { 27 | time.Sleep(1 * time.Second) 28 | req, err := http.NewRequest(http.MethodGet, 29 | "http://localhost:8080/ruta/de/documento", nil) 30 | if err != nil { 31 | panic(err) 32 | } 33 | client := http.Client{ 34 | Timeout: 5 * time.Second, 35 | } 36 | resp, err := client.Do(req) 37 | if err != nil { 38 | panic(err) 39 | } 40 | fmt.Println("Código de respuesta:", resp.StatusCode) 41 | fmt.Println("Content-Type:", resp.Header["Content-Type"]) 42 | cuerpo, err := ioutil.ReadAll(resp.Body) 43 | if err != nil { 44 | panic(err) 45 | } 46 | fmt.Println("---") 47 | fmt.Println(string(cuerpo)) 48 | }() 49 | panic(http.ListenAndServe(":8080", &HolaServicio{})) 50 | } 51 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/go.mod: -------------------------------------------------------------------------------- 1 | module cosafina 2 | 3 | go 1.15 4 | 5 | require gopkg.in/yaml.v2 v2.3.0 6 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/go.sum: -------------------------------------------------------------------------------- 1 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 2 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 3 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 4 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 5 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/serialize.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type Futbolista struct { 9 | Nombre string `json:"nombre"` 10 | Nacimiento int `json:"nacimiento"` 11 | Equipos []string `json:"equipos"` 12 | } 13 | 14 | var cr = Futbolista{ 15 | Nombre: "Carles Reixach", 16 | Nacimiento: 1947, 17 | Equipos: []string{ 18 | "F.C. Barcelona", 19 | "Selección Española de Fútbol", 20 | }, 21 | } 22 | 23 | func main() { 24 | documento := []byte(`{ 25 | "nombre": "Paco Garcia", 26 | "nacimiento": "un dia cualquiera", 27 | "liga": "Liga Peruana" 28 | }`) 29 | var f Futbolista 30 | err := json.Unmarshal(documento, &f) 31 | if err != nil { 32 | fmt.Println("Error decodificando:", err) 33 | return 34 | } 35 | fmt.Printf("decodificado: %#v\n", f) 36 | } 37 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/serializemap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | documento := []byte(`{ 10 | "receta": "Huevos Fritos", 11 | "ingredientes": [ 12 | "Huevos", 13 | "Aceite", 14 | "Sal" 15 | ] 16 | }`) 17 | destino := map[string]interface{}{} 18 | err := json.Unmarshal(documento, &destino) 19 | if err != nil { 20 | fmt.Println("Error decodificando:", err) 21 | return 22 | } 23 | fmt.Println("decodificado:") 24 | for c, v := range destino { 25 | fmt.Printf("%s --> %v\n", c, v) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/serializeslice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | listaJson := []byte(`["hola", "que", "tal"]`) 10 | var lista []string 11 | if err := json.Unmarshal(listaJson, &lista); err != nil { 12 | panic(err) 13 | } 14 | fmt.Println("deserializado:", lista) 15 | lista = append(lista, "amigo") 16 | listaJson2, err := json.Marshal(lista) 17 | if err != nil { 18 | panic(err) 19 | } 20 | fmt.Println("serializado:", string(listaJson2)) 21 | } 22 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/xml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/xml" 5 | "fmt" 6 | ) 7 | 8 | type Animal struct { 9 | Nombre string `xml:"nombre"` 10 | Tipo string `xml:"tipo"` 11 | } 12 | 13 | func main() { 14 | a := Animal{Nombre: "Perro", Tipo: "Mamífero"} 15 | b, err := xml.Marshal(a) 16 | if err != nil { 17 | panic(err) 18 | } 19 | fmt.Println(string(b)) 20 | } 21 | -------------------------------------------------------------------------------- /ejemplos-libro/18-serializacion-datos/yaml.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "gopkg.in/yaml.v2" 7 | ) 8 | 9 | type Alumno struct { 10 | Nombre string `yaml:"nombre"` 11 | Apellido string `yaml:"apellido"` 12 | } 13 | 14 | type Aula struct { 15 | Alumnos []Alumno `yaml:"alumnos"` 16 | } 17 | 18 | func main() { 19 | a := Aula{Alumnos: []Alumno{ 20 | {Nombre: "Carolina", Apellido: "Martínez"}, 21 | {Nombre: "Juan Francisco", Apellido: "Pérez"}, 22 | }} 23 | txt, err := yaml.Marshal(a) 24 | if err != nil { 25 | panic(err) 26 | } 27 | fmt.Println(string(txt)) 28 | } 29 | -------------------------------------------------------------------------------- /ejemplos-libro/19-bases-datos/.gitignore: -------------------------------------------------------------------------------- 1 | archivo.db -------------------------------------------------------------------------------- /ejemplos-libro/19-bases-datos/go.mod: -------------------------------------------------------------------------------- 1 | module ejemplo-sql 2 | 3 | go 1.15 4 | 5 | require github.com/mattn/go-sqlite3 v1.14.2 6 | -------------------------------------------------------------------------------- /ejemplos-libro/19-bases-datos/go.sum: -------------------------------------------------------------------------------- 1 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= 2 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 3 | github.com/mattn/go-sqlite3 v1.14.2 h1:A2EQLwjYf/hfYaM20FVjs1UewCTTFR7RmjEHkLjldIA= 4 | github.com/mattn/go-sqlite3 v1.14.2/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= 5 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 6 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 7 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 8 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 9 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 10 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 11 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 12 | -------------------------------------------------------------------------------- /ejemplos-libro/19-bases-datos/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | // driver 5 | "database/sql" 6 | "fmt" 7 | 8 | _ "github.com/mattn/go-sqlite3" 9 | ) 10 | 11 | type Alumno struct { 12 | Nombre string 13 | Id string 14 | Nota float64 15 | } 16 | 17 | type AccesoDatos struct { 18 | bd *sql.DB 19 | inserta *sql.Stmt 20 | buscaPorNota *sql.Stmt 21 | } 22 | 23 | func NuevoAccesoDatos(bd *sql.DB) (AccesoDatos, error) { 24 | var err error 25 | a := AccesoDatos{bd: bd} 26 | a.inserta, err = bd.Prepare(` 27 | INSERT INTO Alumnos(id, nombre, nota) 28 | VALUES (?, ?, ?)`) 29 | if err != nil { 30 | return a, err 31 | } 32 | a.buscaPorNota, err = bd.Prepare(` 33 | SELECT id, nombre, nota FROM Alumnos 34 | WHERE nota >= ? AND nota < ? 35 | ORDER BY nota 36 | `) 37 | return a, err 38 | } 39 | 40 | func main() { 41 | bd, err := sql.Open("sqlite3", "./archivo.db") 42 | 43 | if err != nil { 44 | panic(err) 45 | } 46 | _, err = bd.Exec(`CREATE TABLE IF NOT EXISTS 47 | Alumnos( 48 | id VARCHAR PRIMARY KEY, 49 | nombre VARCHAR, 50 | nota FLOAT 51 | )`) 52 | if err != nil { 53 | panic(err) 54 | } 55 | defer bd.Close() 56 | 57 | ad, _ := NuevoAccesoDatos(bd) 58 | 59 | aula := []Alumno{ 60 | {Id: "1234A", Nombre: "Jose", Nota: 3.5}, 61 | {Id: "5678B", Nombre: "Lara", Nota: 10}, 62 | {Id: "9101C", Nombre: "Sara", Nota: 7.5}, 63 | {Id: "1121D", Nombre: "Ivan", Nota: 8}, 64 | {Id: "3141E", Nombre: "Juan", Nota: 5.75}, 65 | } 66 | if err := ad.InsertaTodos(aula); err != nil { 67 | fmt.Println("error insertando alumnos:", err) 68 | } 69 | notables, err := ad.BuscaPorNota(7, 9) 70 | if err != nil { 71 | panic(err) 72 | } 73 | fmt.Println("Los alumnos con notable son:") 74 | for _, a := range notables { 75 | fmt.Printf("%+v\n", a) 76 | } 77 | } 78 | 79 | func (d *AccesoDatos) InsertaTodos(aula []Alumno) error { 80 | tx, err := d.bd.Begin() 81 | if err != nil { 82 | return err 83 | } 84 | insertaTx := tx.Stmt(d.inserta) 85 | for _, a := range aula { 86 | _, err := insertaTx.Exec(a.Id, a.Nombre, a.Nota) 87 | if err != nil { 88 | tx.Rollback() 89 | return err 90 | } 91 | } 92 | return tx.Commit() 93 | } 94 | 95 | func (d *AccesoDatos) Inserta(a Alumno) error { 96 | _, err := d.inserta.Exec(a.Id, a.Nombre, a.Nota) 97 | return err 98 | } 99 | 100 | func (d *AccesoDatos) BuscaPorNota( 101 | min, max float64) ([]Alumno, error) { 102 | encontrados, err := d.buscaPorNota.Query(min, max) 103 | 104 | if err != nil { 105 | return nil, err 106 | } 107 | var alumnos []Alumno 108 | for encontrados.Next() { 109 | a := Alumno{} 110 | err := encontrados.Scan(&a.Id, &a.Nombre, &a.Nota) 111 | if err != nil { 112 | return nil, err 113 | } 114 | alumnos = append(alumnos, a) 115 | } 116 | return alumnos, nil 117 | } 118 | -------------------------------------------------------------------------------- /ejemplos-libro/20-testing/fact.go: -------------------------------------------------------------------------------- 1 | package funciones 2 | 3 | import "fmt" 4 | 5 | func Factorial(n uint64) uint64 { 6 | f := uint64(1) 7 | for i := uint64(2); i <= n; i++ { 8 | f *= i 9 | } 10 | return f 11 | } 12 | 13 | func NoProbado() { 14 | fmt.Println("hola!") 15 | } 16 | -------------------------------------------------------------------------------- /ejemplos-libro/20-testing/fact_test.go: -------------------------------------------------------------------------------- 1 | package funciones 2 | 3 | import "testing" 4 | 5 | type ejemploTest struct { 6 | num uint64 7 | esperado uint64 8 | } 9 | 10 | func TestFactorial(t *testing.T) { 11 | ejemplos := []ejemploTest{ 12 | {num: 1, esperado: 1}, 13 | {num: 7, esperado: 5040}, 14 | {num: 10, esperado: 3628800}, 15 | {num: 13, esperado: 6227020800}, 16 | } 17 | for _, ej := range ejemplos { 18 | resultado := Factorial(ej.num) 19 | if resultado != ej.esperado { 20 | t.Errorf("Factorial(%d): Esperaba %d. Retornó %d", 21 | ej.num, ej.esperado, resultado) 22 | } 23 | } 24 | } 25 | 26 | func BenchmarkFactorial(b *testing.B) { 27 | for i := 0; i < b.N; i++ { 28 | _ = Factorial(21) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ejemplos-libro/20-testing/fibonacci.go: -------------------------------------------------------------------------------- 1 | package funciones 2 | 3 | func Fib(n int) []int { 4 | if n == 0 { 5 | return []int{1} 6 | } 7 | seq := make([]int, n+1) 8 | seq[0] = 1 9 | seq[1] = 1 10 | for i := 2; i <= n; i++ { 11 | seq[i] = seq[i-1] + seq[i-2] 12 | } 13 | return seq 14 | } 15 | -------------------------------------------------------------------------------- /ejemplos-libro/20-testing/fibonacci_test.go: -------------------------------------------------------------------------------- 1 | package funciones 2 | 3 | import "testing" 4 | 5 | func TestFib_0(t *testing.T) { 6 | res := Fib(0) 7 | if len(res) != 1 || res[0] != 1 { 8 | t.Errorf("fib(0) expected to be [1]. Got %+v", res) 9 | } 10 | } 11 | 12 | func TestFib_1(t *testing.T) { 13 | res := Fib(1) 14 | if len(res) != 2 || res[0] != 1 || res[1] != 1 { 15 | t.Errorf("fib(1) expected to be [1 1]. Got %+v", res) 16 | } 17 | } 18 | 19 | func TestFib_N(t *testing.T) { 20 | res := Fib(7) 21 | expected := []int{1, 1, 2, 3, 5, 8, 13, 21} 22 | if len(res) != len(expected) { 23 | t.Errorf("fib(7) expected to be %+v. Got %+v", expected, res) 24 | return 25 | } 26 | for i := range expected { 27 | if expected[i] != res[i] { 28 | t.Errorf("fib(7) expected to be %+v. Got %+v", expected, res) 29 | return 30 | } 31 | } 32 | } 33 | 34 | /* ejecutar con: 35 | go test -bench=. 36 | go test -bench=. -benchmem 37 | go test -bench=. -benchmem -benchtime=10s 38 | */ 39 | func BenchmarkFib(b *testing.B) { 40 | for i := 0; i < b.N; i++ { 41 | Fib(10) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /fe-de-erratas.md: -------------------------------------------------------------------------------- 1 | # Fe de erratas 2 | 3 | A pesar de los múltiples procesos de revisión y corrección a los que el libro 4 | ha sido sometido, hemos detectado las siguientes erratas en la primera edición: 5 | 6 | * Página 17, en _Acerca del autor_: donde dice _generación baby boom_ debería decir _generación X_ 7 | * Página 30, tercer elemento de la segunda lista numerada, donde dice `a := 8 + 9` 8 | debería decir `a := 8 + 4` 9 | * Página 31, penúltima fila de la tabla, última columna. Donde dice `3 >= 2 (resultado: false)` 10 | debería decir `3 >= 2 (resultado: true)` 11 | * Página 32, en el cuadro gris de información. Donde dice _y `"ZZZ" < "aaa"` también retornará `false`_, 12 | debería decir _y `"ZZZ" < "aaa"` retornará `true`_ 13 | * Contraportada. Donde dice _en la empresa New Relic_, debería decir _en la empresa Red Hat_. No era una errata, pero es un dato desactualizado. 14 | -------------------------------------------------------------------------------- /wasm-tutorial/README.md: -------------------------------------------------------------------------------- 1 | Go y WebAssembly: interactuando con la API JavaScript de tu Navegador Web 2 | ===================================================== 3 | 4 | Capítulo online para el libro [Programación en Go](https://www.marcombo.com/programacion-en-go-9788426732330/) 5 | de la editorial Marcombo. 6 | 7 | Por [Mario Macías Lloret](http://macias.info). 8 | 9 | [WebAssembly (abreviado WASM)](https://webassembly.org/) promete llevar a un 10 | siguiente nivel la programación sobre navegadores web. Hasta hace poco, los 11 | navegadores solo eran capaces de ejecutar programas escritos en JavaScript/ECMAScript 12 | (en adelante, nos referiremos a este lenguaje como JS). 13 | Si se deseaba programar para el navegador en otros lenguajes, o en versiones muy 14 | modernas de JS, era necesario un transpilador que convertía el código 15 | a una versión de JavaScript aceptada por el navegador. 16 | 17 | JavaScript se interpreta en tiempo de ejecución. Interpretar cadenas de texto 18 | con el programa JS es un proceso relativamente lento, que causa que 19 | las web se vuelvan realmente lentas a medida que se vuelven más sofisticadas. 20 | 21 | WebAssembly, sin embargo, es una especificación de instrucciones sencillas, que 22 | se especifican mediante código binario (como si de las instrucciones de una 23 | CPU física se tratara). Esto no solo disminuye enormemente el tiempo de carga 24 | (los programas a cargar son mucho más pequeños), sino que el tiempo de interpretación 25 | y optimización del programa en tiempo de ejecución también se reduce. 26 | 27 | Otra ventaja es que ahora es posible programar en prácticamente cualquier lenguaje 28 | las aplicaciones que se ejecutarán directamente sobre el navegador web; incluso 29 | en lenguajes que hasta ahora se consideraban más orientados a sistemas de bajo 30 | nivel, como C, C++ o Rust. Esto permite llevar al navegador un gran número de 31 | aplicaciones antiguas escritas en estos lenguajes (videojuegos, aplicaciones 32 | multimedia...). 33 | 34 | Sin embargo, la mayoría de bibliotecas y APIs del Navegador, imprescindibles 35 | para interactuar con éste, siguen proporcionando interfaces JavaScript únicamente. 36 | Este capítulo explica cómo utilizar la librería estándar para la interconexión 37 | de Go con las APIs de JS, permitiendo instanciar objetos, invocar métodos y 38 | funciones, acceder a sus propiedades o incluso proporcionar funciones que se 39 | usarán como [_callback_](https://es.wikipedia.org/wiki/Callback_(inform%C3%A1tica)). 40 | 41 | Go provee el paquete experimental `syscall/js`, que facilita la creación de 42 | aplicaciones para el navegador web sin necesidad de ningún transpilador JS; 43 | simplemente especificando al compilador de Go que la arquitectura de destino 44 | será WASM. Este capítulo explicará cómo compilar de Go a WASM y cómo configurar 45 | una aplicación web para cargar nuestros programas WASM. 46 | 47 | ## Preparando el entorno 48 | 49 | Ejecutar un proyecto de WebAssembly en Go requiere tres archivos: 50 | 51 | * Un archivo con extensión `.wasm`, que contiene los datos binarios de WebAssembly. 52 | Este archivo será generado por el compilador de Go. 53 | * Un fichero `wasm_exec.js`, proporcionado por el equipo de Go para poder cargar 54 | el archivo `.wasm` dentro de la página web. 55 | * Un fichero HTML que carga el archivo `wasm_exec.js` y lo configura para 56 | cargar y ejecutar el código `.wasm` en el navegador. 57 | 58 | Además, será necesario un servidor Web para cargar los anteriores archivos mediante 59 | HTTP o HTTPS. Se puede utilizar cualquier servidor HTTP simple, aunque en este 60 | capítulo crearemos nuestro servidor HTTP para probar el código de los tutoriales 61 | sin tener que instalar ni configurar software adicional en nuestro ordenador. 62 | 63 | ## Creación del proyecto 64 | 65 | Nuestro proyecto Go/WASM tendrá la siguiente estructura de directorios y 66 | archivos: 67 | 68 | ``` 69 | . 70 | ├── server.go 71 | ├── site 72 | │ ├── index.html 73 | │ ├── main.wasm 74 | │ └── wasm_exec.js 75 | └── src 76 | └── main.go 77 | ``` 78 | 79 | * El directorio `site` contendrá los archivos mínimos indispensables para ejecutar 80 | un programa WASM en el navegador, tal y como se mencionó anteriormente. 81 | * El programa `server.go` es un sencillo navegador Web de pruebas que servirá 82 | para cargar desde el navegador Web los archivos de la carpeta `site`. 83 | * El directorio `src` contiene el código Go que se compilará en el archivo 84 | `site/main.wasm`. 85 | 86 | 87 | ## Obtención de `wasm_exec.js` 88 | 89 | El fichero `wasm_exec.js` está disponible en la instalación estándar de Go, 90 | bajo el directorio `${GOROOT}/misc/wasm/wasm_exec.js`. Para saber la localización 91 | de `${GOROOT}` puede ejecutar el comando `go env GOROOT`. Por ejemplo: 92 | 93 | ``` 94 | $ go env GOROOT 95 | /usr/local/Cellar/go/1.15.3/libexec 96 | ```` 97 | 98 | La salida anterior indicaría que el fichero `wasm_exec.js` se encuentra, en el 99 | ordenador en que se ha ejecutado el comando, en la ruta: 100 | 101 | ``` 102 | /usr/local/Cellar/go/1.15.3/libexec/misc/wasm/wasm_exec.js 103 | ``` 104 | 105 | Puede copiar directamente ese archivo a la carpeta `site` del proyecto. Por 106 | ejemplo, en Linux o Mac: 107 | 108 | ``` 109 | cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" ./site/ 110 | ``` 111 | 112 | ### 3. Crear el fichero HTML 113 | 114 | Cree el fichero `index.html`, por ejemplo, en la carpeta `site` del proyecto. 115 | Copie el siguiente contenido: 116 | 117 | ```html 118 | 119 | 120 | 121 | 122 | 129 | 130 | 131 | 132 | 133 | ``` 134 | 135 | Este archivo está vacío. Simplemente carga el fichero `wasm_exec.js`, que 136 | a su vez cargará el fichero `main.wasm` que se creará en la siguiente 137 | sección. 138 | 139 | ## Compilación de código Go en `main.wasm` 140 | 141 | Como prueba, crearemos un programa de prueba muy sencillo, en la ruta 142 | `./src/main.go` del proyecto: 143 | 144 | ```go 145 | package main 146 | 147 | import "log" 148 | 149 | func main() { 150 | log.Println("¡Hola, Wasmeros!") 151 | } 152 | ``` 153 | 154 | Para compilarlo, es necesario ejecutar el comando `go build`, pero con 155 | las variables de entorno `GOOS=js` y `GOARCH=wasm` para indicar a `go build` 156 | que el archivo generado no será un ejecutable nativo sino un archivo WASM: 157 | 158 | ``` 159 | GOOS=js GOARCH=wasm go build -o ./site/main.wasm ./src/. 160 | ``` 161 | 162 | ## Ejecución del binario WASM 163 | 164 | Por seguridad, su navegador Web no ejecutará el fichero WASM si abre el archivo 165 | `index.hml` directamente en su navegador web. Necesitará un servidor Web que 166 | le envíe toda la información al navegador vía HTTP o HTTPS. 167 | 168 | No es necesario que se moleste a instalar un servidor en la máquina que usa 169 | para programar. Por suerte, crear un servidor Web sencillo en Go es tan sencillo 170 | como crear el fichero `server.go` en la raíz del proyecto, con el siguiente 171 | contenido: 172 | 173 | ```go 174 | package main 175 | 176 | import ( 177 | "fmt" 178 | "io" 179 | "net/http" 180 | "os" 181 | "path/filepath" 182 | ) 183 | 184 | func main() { 185 | http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 186 | // por defecto, cargamos el archivo `index.html` 187 | if req.RequestURI == "/" { 188 | req.RequestURI = "/index.html" 189 | } 190 | // si no, el archivo que nos llegue por la URL lo iremos a buscar 191 | // a la carpeta "site" 192 | file, err := os.Open(filepath.Join("./site", req.RequestURI)) 193 | if err == nil { 194 | // mandamos el contenido del archivo leído hacia la respuesta HTTP 195 | io.Copy(w, file) 196 | } 197 | // por sencillez, ignoramos cualquier gestión de errores HTTP 198 | // por ejemplo, si no se encuentra un archivo 199 | }) 200 | // el servidor escuchará en el puerto 8080 de la máquina local 201 | fmt.Println(http.ListenAndServe(":8080", nil)) 202 | } 203 | ``` 204 | 205 | Las diversas funciones y elementos del programa anterior están explicadas en 206 | en los siguientes capítulos del libro *Programación en Go*: 207 | 208 | * Capítulo 13: Gestión de errores 209 | * Capítulo 14: Entrada y Salida 210 | * Capítulo 17: Servicios Web 211 | 212 | Si ejecuta el servidor mediante `go run server.go` y abre la dirección local 213 | `http://localhost:8080` del navegador, debería ver una ventana vacía. Pero 214 | si abre la Consola en las herramientas de desarrollador de su navegador, 215 | debería ver un mensaje similar al siguiente, mostrando que el archivo WASM 216 | se ha ejecutado: 217 | 218 |  219 | 220 | El resultado puede ser un poco decepcionante. Para permitir a nuestro programa 221 | en Go interactuar con el documento HTML y leer/escribir contenidos en éste, 222 | deberemos utilizar los métodos del paquete `syscall/js`. 223 | 224 | ## Funcionalidades básicas de `syscall/js` basic functionalities 225 | 226 | Organizaremos una ruta a través de las funcionalidades básicas de `syscall/js` 227 | con un ejemplo sencillo que, cada vez 228 | que se haga click en la ventana, añada una línea mostrando `¡click!` en el 229 | documento HTML. 230 | 231 |  232 | 233 | 234 | En Javascript, se requerirían las siguientes líneas de código: 235 | 236 | ```js 237 | document.body.onclick = function() { 238 | var div = document.createElement('div'); 239 | div.textContent = '¡clic!'; 240 | document.body.appendChild(div); 241 | }; 242 | ``` 243 | 244 | El equivalente en Go requeriría acceder a los mismos 245 | elementos y propiedades, pero no directamente a través del 246 | lenguaje sino a través de diversos método de la biblioteca 247 | `syscall/js`: 248 | 249 | 250 | ```go 251 | 1: package main 252 | 2: 253 | 3: import "syscall/js" 254 | 4: 255 | 5: func main() { 256 | 6: window := js.Global() 257 | 7: doc := window.Get("document") 258 | 8: body := doc.Get("body") 259 | 9: body.Set("onclick", 260 | 10: js.FuncOf(func(this js.Value, args []js.Value) interface{} { 261 | 11: div := doc.Call("createElement", "div") 262 | 12: div.Set("textContent", "¡clic!") 263 | 13: body.Call("appendChild", div) 264 | 14: return nil 265 | 15: })) 266 | 16: <-make(chan struct{}) 267 | 17: } 268 | ``` 269 | 270 | La función `js.Global()` de la línea 6 retorna el objeto global. Generalmente 271 | equivaldría a la variabla global `window` en JavaScript: el objeto raíz que 272 | permite acceder a los demás elementos de la página. En el anterior ejemplo de 273 | JavaScript no era necesario mencionarlo, pero en Go sí, ya que no se asume 274 | ningún contexto por defecto. 275 | 276 | `js.Global()` retorna un objeto del tipo `js.Value`: un estructura que puede guardar un valor de cualquier tipo de dato 277 | de JavaScript. 278 | 279 | El método `Get` invocado sobre cualquier `js.Value` permite 280 | acceder a una propiedad de ese valor, retornando otro `js.Value`. 281 | Por ejemplo, `window.Get("document")` en la línea 7 equivaldría 282 | a invocar `window.document` en JavaScript, y `doc.Get("body")` 283 | de la línea 8 equivaldría a invocar `document.body` en JavaScript. 284 | 285 | Si `Get` nos permite acceder al valor de una propiedad, `Set` permite 286 | cambiar dicho valor. El comando `div.Set("textContent", "¡clic!")` de la 287 | línea 12 equivaldría a la línea `div.textContent = '¡clic!';` de JavaScript. 288 | El primer comando de `Set` es un `string` con el nombre de la propiedad a 289 | añadir o cambiar, el segundo comando puede ser un tipo de dato básico (números, 290 | cadenas, ...) pero también puede ser otro `js.Value` o incluso una función, 291 | que en Go se representa según el tipo `js.Func`, y se puede instanciar 292 | mediante la función `js.FuncOf`, como se muestra en la línea 10. Las 293 | líneas 9 y 10 del ejemplo equivalen a la orden `document.body.onclick = function() {` de JavaScript. 294 | 295 | Para invocar métodos JavaScript, el código de ejemplo también utiliza el método `Call` de 296 | `js.Value`. `Call` necesita, como primer argumento, el nombre de la función 297 | o método a invocar, seguido de los argumentos que esta requiera. El ejemplo 298 | de la línea 11 equivaldría a la invocación `document.createElement("div")` y 299 | el de la línea 13 equivaldría a `body.appendChild(div)`. Después del 300 | primer argumento de `Call`, que ha de ser del tipo `string`, los demás argumentos 301 | pueden ser tipos de datos básicos, `js.Value`, o incluso otros `js.Func`. 302 | 303 | ## Aislando la interacción con JavaScript detrás de bibliotecas 304 | 305 | No le negaré que el ejemplo de la sección anterior puede resultar decepcionante. Lo que 306 | en JavaScript podía especificarse en 4 líneas, ha requerido de al menos 9 líneas de Go, 307 | con un léxico mucho más retorcido. 308 | 309 | Sin embargo, puede aislar la interacción con JavaScript detrás de tipos de datos y métodos de Go, 310 | de tal manera que usted pueda centrarse en el uso de Go para programar la Web. 311 | 312 | Como ejemplo, vamos a realizar una animación en Go sobre un elemento Canvas de HTML: 313 | 314 |  315 | 316 | Para ello, vamos a hacer uso del módulo externo [Gorrazo](https://github.com/mariomac/gorrazo), 317 | que le permite gestionar y dibujar sobre un objeto Canvas situado en su página web. 318 | 319 | Para ello, primeramente es necesario incorporar el siguiente módulo en su `go.mod`: 320 | 321 | ``` 322 | github.com/mariomac/gorrazo 323 | ``` 324 | 325 | Para saber cómo hacerlo, puede consultar el capítulo 9 del libro Programación en Go, sobre la organización del código. 326 | 327 | A continuación, será necesario añadir el siguiente elemento `