Intro

  • https://golangr.com/ --> Concurrency
  • https://gobyexample.com
  • https://github.com/enocom/gopher-reading-list
  • https://golangresources.com/
  • http://www.golangbootcamp.com/book

En .bashrc:

export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=$HOME/go

Compilar

go build -ldflags=-w prog.go

Instalar paquetes

go get github.com/fatih/color

Comentarios

// Una linea
/* Varias
lineas */

Ver tipo de variable y variable formateada:

package main
import "fmt"
func main() {
    var j int = 27
    fmt.Printf("%v, %T",j,j) --> %v valor, %T type.
}

Variables

Declarar variables

Hay 3 formas de declarar variables:

1) var i int
i= 42
2) var j int = 22
3) k := 99
1-1) var nombre, apellido string
3-3) usuario1 , usuario2 := "emely", "joaquin"

La primera te permite inizializar la varaible aunque no la uses hasta mas tarde. La 2 te permite tener mas control sobre el tipo de dato que quieres que sea.

Se pueden crear todas las variables en un bloque:

var(
    actorName string = "Eli"
    companion string = "Sarah"
    season int = 11
)

Castear variables

var i int = 42
var j float 32
j = float32(i)

Convertir int a String.

import "strconv"

var i int = 42
var j string
j = strconv.Itoa(i)

Declarar constante

const nombre = "Dickson"
const myConst int = 42

Declarar Slices

var nombres []string
//Otra manera de declarar slices
nombres := make([]string, 0)

Declarar Array

var arr1 = new([5]int)
Otra forma es:
grade := [3]int{32,54,34}

Constantes

El valor de una constante no se pueden cambiar

const nombre = "Dickson"
fmt.Println(nombre)

Arrays

Un array solo puede guardar un tipo de dato.

grades := [3]int{32,54,34}g
grades := [...]int{34,43,43} -> Implementa los arrays que haya.

var students [3]string --> Array sin inicializar.
apellidos := [3]string{"Garcia", "Zerpa", "GarciaZerpa"} --> Array inicializado
students[0] = "Lisa"

Ver tamaño de un array:

var students [5]string
fmt.Prinf("Number of Students: %v\n", len(students))

Los arrays se pueden copiar.

grades := [3]int{32,54,34}
grades2 := grades

Si se modifica grades2 no afecta a grades.

Slices

a := make([]int, 3)
// 2 forma de declarar slices.
a := []int{1,2,3}
b := a[:] -> Copia todos los elementos.
c := a[:6] -> Copia los primeros 6 elementos.
d := a[3:6] -> Copia 4,5, y 6.
a = append(a, 1) -> Agrega el elemento 1 al slice "a".
fmt.Prinf("Capacidad: %v\n", cap(a))
//Otra forma de agregar informacion a nuestro slices
apellidos := []string{
"Garcia",
"Zerpa",
"Rincon",
}


Eliminar el ultimo elemento

b := a[:len(a)-1] 
a = append(a, 1,2,3,4) es igual a:
a = append(a, []int{1,2,3,4}...)

Los slices e pueden copiar. Si se modifica b afecta a a.

a := []int{1,2,3}
b := a
b[2] = 3

Maps

statePopulations := map[string]int{
"California": 432423
"Texas":9874389743
}
fmt.Println(statePopulations) --> Printaria todo el map.
fmt.Println(statePopulations["Texas"]) -> Printaria 9874389743

Modificar Valor:

statePopulations["Texas"] = 897329873289

Borrar valor:

delete(statePopulations,"Texas") --> Elimina Texas

pop, ok := statePopulations["Oho"] fmt.Println(pop,ok) -> Printa 0, false porque Oho no existe.

Formas de declarar un map:

1) statePopulations := map[string]int
2) statePopulations := make(map[string]int)

Al copiar maps, si se manipula cambia en el original.

Struct

Declarar Struct

//Declarar struct

var suscriptor struct{
    nombre string
    activo bool
    puntuacion int
}

Declarar Type

type Doctor struct {
    number int
    actorName string
    companions []string
}

func main(){
    aDoctor := Doctor{
        number: 3,
        actorName: "Jon",
        companions: []string{
            "Liz",
            "Jo",
        },
    }
    fmt.Println(aDoctor)
    fmt.Println(aDoctor.number)
    fmt.Println(aDoctor.companions[1])
}

La forma:

type Doctor struct {
    name string
}

Es equivalente a:

aDoctor := struct{name string}{Name:"John"}

Cuando se copia un struct y se modifica, no se modifica el original. Para manipularlo:

aDoctor := struct{name string}{Name:"John"}
anotherDoctor := &aDoctor

Otro ejemplo:

type Animal struct {
    Name string
    Origin string
}
type Bird struct {
    Animal <-- Se inserta el struct superior.
    Speed float
    CanFly bool
}
b := Bird{}
b.Name = "Emu"
b.Origin = "Austraila"
b.Speed = 43
b.CanFly = false

Otro ejemplo:

type car struct {
    name string
    speed float64
}

var porshe car
porshe.name = "911 R"
porshe.speed = 323

IF

// or || // and && // not ! i := 25 //IF if i > 30 || i < 26 { fmt.Println("I es mayor a 24") } // IF ELSE //if i < 30 { //fmt.Println("I es menor a 30") //} else { //fmt.Println("Esto es el else") //}

// IF ELSE IF ELSE
//if num := 9; num < 0 {
//fmt.Println(num, "is negative")
//} else if num < 10 {
//fmt.Println(num, "has 1 digit")
//} else {
//fmt.Println(num, "has multiple digits")
//}

}

Switch

package main import "fmt" func main() { //ejemplo 1 / var a uint8 a = 3 switch a { case 1: fmt.Println("Domingo") case 2: fmt.Println("Lunes") case 3: fmt.Println("Martes") case 4: fmt.Println("Miercoles") case 5: fmt.Println("Jueves") case 6: fmt.Println("Viernes") case 7: fmt.Println("Sabado") default: fmt.Println("No es un dia de la semana") } /

//Ejemplo 3
switch a := 7; {
case a >= 0 && a <= 5:
    fmt.Println("Estas entres semana")
case a >= 6 && a <= 7:
    fmt.Println("Estas en fin de semana")
default:
    fmt.Println("No es un dia valido")
}

}

Bucles

package main import "fmt" func main() {

// For1
//count := 0
//for count <= 10 {
//  fmt.Println(count)
//  count++
//}

// For2
for i := 1; i < 10; i++ {
    fmt.Println(i)
}

}

Para recorrer slices por ejemplo: s := []int{1,2,3} for k,v := range s { fmt.Println(k,v) }

MAPS

//Declaracion de maps
/*
    idiomas := make(map[string]string)
    idiomas["es"] = "Español"
    idiomas["en"] = "Inglés"
    idiomas["fr"] = "Francés"
*/

//otra forma de Declaracion de maps
idiomas := map[string]string{
    "es": "Español",
    "en": "Inglés",
    "fr": "Francés",
}
//imprimir todo el mapa
fmt.Println(idiomas)
//imprimir solo una posicion en especifico
fmt.Println(idiomas["fr"])
//eliminar una posicion del mapa
delete(idiomas, "en")
fmt.Println(idiomas)

// comprobar si una posicion existe
if idioma, ok := idiomas["en"]; ok {
    fmt.Println("La posicion en si existe y vale ", idioma)
} else {
    fmt.Println("La posicion NO existe")
}

//declaracion de maps con int y string
numeros := map[int]string{
    1:  "un numero pequeño",
    20: "otro numero",
    -3: "llave negativa",
}
fmt.Println(numeros)

}

Defer

Se suele utilizar para: Abrir fichero. Comprobara errores. Defer close fichero.

func main(){ fmt.Println("start) defer fmt.Println("middle") fmt.Println("end") }

Panic

package main import ( "fmt" ) func main(){ fmt.Println("start") panic("Wrong") fmt.Println("end") }

Punteros

var a int = 42 var b int = &a fmt.Println(a, b)

Funciones

package main
import (
    "fmt"
)

func main() {
    sayMessage("hello Go!")
}
func sayMessage(msg string){
    fmt.Println(msg)
}

Pasar punteros.

package main
import (
    "fmt"
)

func main() {
    greeting := "Hello"
    name := "Richard"
    sayMessage(&greeting, &name)
}
func sayMessage(greeting,name *string){
    fmt.Println(*greeting,*name*)
}

Retornar valores funcion

package main
import (
    "fmt"
)

func main() {
    s := sum(1,2,3,4,5)
    fmt.Println("La suma es",s)
}
func sum(values ...int) int{
    result := 0
    for _, v := range values {
        result += v
    }
    return result
}

Tambien se puede usar:

package main
import (
    "fmt"
)

func main() {
    s := sum(1,2,3,4,5)
    fmt.Println("La suma es",s)
}
func sum(values ...int) (result int){
    result := 0
    for _, v := range values {
        result += v
    }
    return 
}

Retornar valores y error

package main
import (
    "fmt"
)

func main() {
    s, err := divide(5,0)
    if err != nil{
        fmt.Println(err)
        return
    }
    fmt.Prinln(s)
}
func divide(a ,b int) (int,error){
    if b == 0 {
        return 0, fmt.Errorf("No se puede dividir por 0")
    }
    return a/b, nil
}

Multiples retornos

package main

import "fmt"

func values() (int, int) {
   return 2,4
}

func main() {
   x, y := values()
   fmt.Println(x)
   fmt.Println(y)
}

Funcion variadica

Las funciones variadicas acepta un numero indeterminado de argumentos.

package main

import "fmt"

func sum(numbers ...int) {
    total := 0
    for _, num := range numbers {
        total += num
    }
    fmt.Println(total)
}

func main() {
    sum(2, 3, 4)
}

Funcion anonima

package main

import "fmt"

func main() {
    func() {
        fmt.Prinln("Hello")
    }()
}

Otro ejemplo

package main

import "fmt"

func main() {
    for i :=0;i<5;i++{
    func(i int) {
        fmt.Prinln(i)
    }(i)
}
}

Usar funciones como variables

package main

import "fmt"

func main() {
    var f func() = func() { // o f := func() { ...}
        fmt.Prinln("Hello")
    }
    f()
}

Funciones con type

package main
import "fmt"
type car struct {
    name string
    speed float64
}
func showInfo(p car){
    fmt.Println("Nombre",p.name)
    fmt.Println("Speed",p.speed)
}
func main(){
    var porshe car
    porshe.name="911"
    porshe.speed="333"
    showInfo(porshe)
}

Funciones con type y punteros.

package main
import "fmt"
type suscriptor struct{
    nombre string
    activo bool
    puntuacion int
}

func desactivar(s *suscriptor){
    s.activo = false
}

func main(){
    var s suscriptor
    desactivar(&s)
    fmt.prinln(s.activo)
}

FOR

package main import "fmt" func main() { // ejemplo 1 / count := 5 for i := 0; i < count; i++ { fmt.Println(i) } /

// ejemplo 2
/*
            for i := 5; i >= 0; i-- {
                if i == 3 {
          fmt.Println("Se salta el valor 3")
                    continue
                }
                fmt.Println(i)
            }
*/

// ejemplo 3
/*
    count := 5
    for i := 0; i < count; i++ {
        if i == 2 {
            fmt.Println("Cuando i vale 2 se rompe el ciclo")
            break
        }
        fmt.Println(i)
    }
*/

// ejemplo 4
matriz := [3][3]int{}
valor := 0
for i := 0; i < 3; i++ {
    for y := 0; y < 3; y++ {
        valor++
        matriz[i][y] = valor
    }

}
for i := 0; i < 3; i++ {
    for y := 0; y < 3; y++ {
        fmt.Println(matriz[i][y])
    }
}

}

Interfaces

package main
import "fmt"
func main() {
    var w Writer ()) ConsoleWriter{}
    w.Write([]byte("Hello Go"))
}

type Writer interface {
    Writer([]byte) (int,error)  
}

type ConsoleWriter struct{}

func (cw ConsoleWriter) Write(data []byte) (int,error){
    n, err := fmt.Println(string(data))
    return n, err
}

Otro ejemplo

package main
import "fmt"
func main() {
    myInt := IntCounter(0)
    var inc Incrementer = &myInt
    for i:=0;i<10;i++{
        fmt.Println(inc.Increment())
    }
}

type Incrementer interface {
    Increment() int 
}

type IntCounter int

func (ic *IntCounter*) Increment () int{
    *ic++
    retur int(*ic)
}
}

GOROUTINES

package main
import "fmt"
func main(){
    go sayHello()
    time.Sleep(100 * time.Millisecond)
}

func sayHello(){
    fmt.Println("Hello")
}

Otro ejemplo

package main
import "fmt"

var wg = sync.WaitGroup{}

func main(){
    var msg = "hello"
    wg.Add(1)
    go func(msg string) {
        fmt.Println(msg)
        wg.Done()
    }(msg)
    wg.Wait()
}

En el siguiente ejemplo hay una race condition:

var wg = sync.Waitgroup{}
var counter = 0
func main(){
    for i := 0;i<10;i++{
        wg.Add(2)
        go sayHello()
        go increment()
    }
    wg.Wait()
}

func sayHello(){
    fmt.Printf("Hello %v",counter)
    wg.Done()
}
func increment(){
    counter++
    wg.Done()
}

Para solucionarlo se usa mutex pero rompe la concurrencia:

var wg = sync.Waitgroup{}
var counter = 0
var m = sync.RWMutex{} //agregada

func main(){
    runtime.GOMAXPROCS(100) //agregada
    for i := 0;i<10;i++{
        wg.Add(2)
        m.RLock()
        go sayHello()
        m.Lock()
        go increment()
    }
    wg.Wait()
}

func sayHello(){
    fmt.Printf("Hello %v",counter)
    m.RUnlock() //agregada
    wg.Done
}
func increment(){
    counter++
    m.Unlock() //agregada
    wg.Done()
}

DETECTAR RACE CONDITION

go run -race file.go

Mirar Threads

import runtime
func main(){
    runtime.GOMAXPROCS(1) //Sirve para asignar solo un Core.
    fmt.Printf("Threads: %v",runtime.GOMAXPROCS(-1))
}

CHANNELS

package main
import (
    "fmt"
    "sync"
)

var wg = sync.Waitgroup{}

func main() {
    ch := make(chan int)
    wg.Add(2)
    go func() {
        i := <- ch
        fmt.Println(i)
        wg.Done()
    }()
    go func(){
        ch <-42
        wg.Done()
    }()
    wg.Wait()
}

BUFFER CHANNEL

package main
import (
    "fmt"
    "sync"
)

var wg = sync.Waitgroup{}

func main() {
    ch := make(chan int,50)
    wg.Add(2)
    go func(ch <-chan int) {
        for i := range ch{
            fmt.Println(i)
        }
        wg.Done()
    }(ch)
    go func(ch chan<- int){
        ch <-42
        ch <-27
        close(ch)
        wg.Done()
    }(ch)
    wg.Wait()
}

FOR INFINITO

package main
import "fmt"
func main() {
    // For continuo es similar a un while en otros lenguajes
    a := 5
    for a > 0 {
        a--
        fmt.Println(a)
    }
}

Otra forma:

package main

import "fmt"

func main() {

    for {
        fmt.Println("Esto no se va a detener")
    }
}

FOR RANGE

    numeros := []string{"cero", "uno", "dos", "tres"}

    // el range devuelve dos valores el indice y el valor
    for i, v := range numeros {
        fmt.Println(i, v)
    }

    //si no queremeos utilizar el indice de coloca _
    for _, v := range numeros {
        fmt.Println(v)
    }

    // El valor se puede omitir en un range
    for i := range numeros {
        fmt.Println(i)
    }

    //ejemplo con mapas funciona de la misma forma
    nombres := map[string]string{
        "es": "España",
        "co": "Colombia",
        "br": "Brasil",
    }
    for i, v := range nombres {
        fmt.Println(i, v)
    }

    // Iteracion de string
    frase := "Hola Mundo"
    for posicion, letra := range frase {
        //fmt.Println(posicion, letra)
        fmt.Println(posicion, string(letra))
    }

    // Iterar slices de entreros
    for _, entero := range []int{15, 36, 24, 87} {
        fmt.Println(entero)
    }

    // Iterar un string
    for _, letra := range "Hola Mundo" {
        fmt.Println(string(letra))
    }
}

EJERCICIOS

Crear un paquete

Creamos la carpeta: mkdir /usr/local/go/src/saludo Creamos el paquete con las funciones: saludo.go

package saludo
import "fmt"
func Hola(){
    fmt.Prinln("HOLA")
}

Ya podemos usar las funciones:

prueba.go

package main
import "saludo"
func main(){
    saludo.Hola()
}

Hello World

package main
import "fmt"
func main() {
    fmt.Println("Hola, Primer Hola Mundo en GoLang ")
}

Concatenar Strings

package main

import "fmt"

func main() {
    str1 := "Hello"
    str2 := "World"
    fmt.Println(str1 + " " + str2)
}

Concatenar Strings con Join

package main

import (
    "fmt"
    "strings"
)

func main() {
    str1 := strings.Join([]string{"Hello", "World", "Test"}, ", ")
    fmt.Println(str1)
}

Output: Hello, World, Test

Entrada por teclado

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    fmt.Println("Enter your name:")
    name, _ := reader.ReadString('\n')
    fmt.Printf("Your name is %v", name)
}

Recorrer Array

package main

import (
    "fmt"
)

func main() {
    array := [3]int{1, 2, 3}
    for i := 0; i < len(array); i++ {
        fmt.Println(array[i])
    }
}

Usar range

package main

import (
    "fmt"
)

func main() {
    array := []int{1, 2, 3}
    for _, elemento := range array {
        fmt.Println(elemento)
    }
}

Comprobar existe un fichero

package main

import (
    "fmt"
    "os"
)

func main() {
    if _, err := os.Stat("/etc/passwd"); err == nil {
        fmt.Println("File exists")

    } else {
        fmt.Println("No existe")
    }
}

Leer fichero

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    file, err := ioutil.ReadFile("/etc/hosts")
    if err != nil {
        fmt.Println(err)
    }
    strfile := string(file)
    fmt.Println(strfile)
}

Leer fichero linea por linea

package main

import (
  "bufio"
  "fmt"
  "log"
  "os"
)

func readLines(path string) ([]string, error) {
  file, err := os.Open(path)
  if err != nil {
    return nil, err
  }
  defer file.Close()
  var lines []string
  scanner := bufio.NewScanner(file)
  for scanner.Scan() {
    lines = append(lines, scanner.Text())
  }
  return lines, scanner.Err()
}

func main() {
  lines, err := readLines("read2.go")
  if err != nil {
    log.Fatalf("readLines: %s", err)
  }
  for i, line := range lines {
    fmt.Println(i, line)
  }
}

Escribir en un fichero

package main

import "os"

func main() {
    file, err := os.Create("file.txt")

    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("write file in golang")
}

Renombrar fichero

package main

import "os"

func main() {
  // source and destionation name
  src := "hello.txt"
  dst := "golang.txt"

  // rename file
  os.Rename(src, dst)
}

Numero random

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func random(min int, max int) int {
    return rand.Intn(max-min) + min
}

func main() {
    rand.Seed(time.Now().UnixNano())
    randomNum := random(0, 10)
    fmt.Printf("Random number: %d\n", randomNum)
}

Metodo

fmt.println("hola") Llama a la funcion println que pertenece al paquete fmt.

var myTime time.Time myTime.Year() Llama al metodo que pertenece al valor Time.

package main

import "fmt"

func main() {
    var str1, str2 string = "Hello", "World"
    var ret = join(str1, str2)
    fmt.Printf("Value is : %v", ret)
}

func join(str1, str2 string) string {
    var result string
    result = str1 + str2
    return result
}

Otro ejemplo

type greeter struct{
    greeting string
    name string
}

func (g greeter) greet() {
    fmt.Println(g.greeting, g.name)
}

func main(){
    g := greeter{
        greeting: "Hello",
        name:"Go",
    }
    g.greet()
}

Otro ejemplo:

type MyType string
func (m MyType) sayHi(){
    fmt.Println("Hi")
}
func main(){
    value := MyType("Un valor")
    value.sayHi()
}

METODO CON PUNTERO

type Number int
func (n *Number) Double(){
    *n *=2
}
func main(){
    number :=Number(4)
    number.Double()
}

CLOSURE

package main

import "fmt"

func makeSequence() func() int {
    i := 1
    return func() int {
        i += 2
        return i
    }
}

func main() {
    sequenceGenerator := makeSequence()
    fmt.Println(sequenceGenerator())
    fmt.Println(sequenceGenerator())
    fmt.Println(sequenceGenerator())
}

PANIC

package main

import "os"

func main(){
    _, err := os.Create("/root/example")
    if err != nil {
        panic("Cannot create file")
    }
}           

ERRORS

package main

import "errors"
import "fmt"

func do() (int, error) {
    return -1, errors.New("Something wrong")
}

func main() {
    fmt.Println( do() )
}

$ go run example.go
-1 Something wrong

r, e := do()
if r == -1 {
    fmt.Println(e)
} else {
    fmt.Print("Everything went fine\n")
}

Strings multilinea

func main() {
    color.Blue(`
    dsadsadsa
    Test blue`)
}

str := `Super
string
multilinea`

Colores

package main

import (
    "github.com/fatih/color"
)

func main() {
    color.Blue(`
    dsadsadsa
    Test blue`)
}

Eliminar salto de linea de string.

read_line = strings.TrimRight(read_line, "\r\n")

Comprimir tamaño

go build -ldflags="-s -w" main.go
https://upx.github.io/
upx main

Escribir fichero en go

package main

import (
    "io/ioutil"
    "log"
)

func main() {
    b := []byte("Hola mundo!\n")
    err := ioutil.WriteFile("personal.txt", b, 0644)
    if err != nil {
        log.Fatal(err)
    }
}

Leer fichero en go

package main

import (
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    // leer el arreglo de bytes del archivo
    datosComoBytes, err := ioutil.ReadFile("empleados.txt")
    if err != nil {
        log.Fatal(err)
    }
    // convertir el arreglo a string
    datosComoString := string(datosComoBytes)
    // imprimir el string
    fmt.Println(datosComoString)
}

String to Slice

memorysplit := strings.Fields(memory)

HTTP Handling

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
)

func main() {

    fileServer := http.FileServer(http.Dir("/var/www/html"))
    http.Handle("/nt4share", fileServer)

    http.HandleFunc("/index", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hi!\n")
    })

    fmt.Printf("Starting server at port 8080\n")
    log.Fatal(http.ListenAndServe(":8080", nil))
}