Personal Website

My Web: MindEchoes.com

Tuesday, March 23, 2010

Jugando con Go

Bueno, andaba con ganas de postear algo, y se me ocurrió empezar a hacer mini-programitas usando Go (el lenguaje de Google), y de paso no colgarme y empezar a hacer algo con este lenguaje como para ir aprendiendo sino me quedo en lo básico nomas... pero bueno, ahora empecemos por lo básico:

Qué es Go y Como Instalarlo??: Post en MundoGeek

Compilando con Go
Como se ve en el Post de MundoGeek, hay diversas formas de compilar según la arquitectura, en mi caso, en Ubuntu en lugar de andar usando "6g" o "6l", directamente lo que hice fue en el archivo ".bashrc" en el "home" fue agregar o descomentar las lineas:


if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi

Lo cual permite cargar el archivo ".bash_aliases" si existe, y en ese archivo crear alias para ciertos comandos que quiera ejecutar para que sean mas directos o fáciles de recordar, como por ejemplo:

Contenido de ".bash_aliases":

alias goc='6g'
alias go='6l -o prog'

De esta forma, ahora para compilar mi programa que se encuentre en un archivo de nombre "programa.go" solo tendría que hacer:

$ goc programa.go
(se crea el archivo programa.6 o programa.8 según la arquitectura)


$ go programa.6
(en mi caso es "6" por ser de 64 bits, y por como quedo configurado el alias, el ejecutable se llamaría "prog", esa parte del alias podría omitirse si quisiéramos darle nombre a cada programa en particular, en mi caso lo puse así porque como estoy haciendo ejemplos para aprender y probar todos en carpetas distintas se me hacia mas rápido)

Y por ultimo podemos hacer:
$ ./prog
Y ejecutamos el programa!

Para que un programa sea ejecutable en Go debe declararse que su paquete sea "main" (al menos el archivo por donde comienza la ejecución). La función "main" del paquete "main" es donde el programa comienza su ejecución.

Típico "Hola Mundo":
package main
import "fmt"
func main(){
    fmt.Printf("Hola mundo\n");
}

El paquete "fmt" es el que se encarga de las entradas y salidas formateadas (vendría a ser algo así como el "stdio.h" de C para usar el printf... solo que acá es... Printf! jeje)
Las funciones son declaradas en Go con la palabra reservada "func".

Un detalle en cuanto a las funciones en Go, es que en lugar de utilizar las palabras reservadas "private" o "public" como en muchos lenguajes para especificar el tipo de acceso a la función, esto se denota colocando la primer letra del nombre del método en Mayúscula para el acceso Publico o en Minuscula para el acceso Privado.
Otro tema interesante es la inicialización de variables que puede omitirse el tipo y hay varias formas de declarar las variables, pero sera un tema para el próximo post.

En este Post no voy a profundizar mucho mas en el lenguaje (sobre todo porque recién lo estoy aprendiendo), sino que voy a ir directo a algunos ejemplos básicos:

Ejemplo Simple de Iteración:
package main
import "fmt"
func main(){
    for i:= 0; i < 10; i++ {
        fmt.Printf("Hola %d\n", i)
    }
}

Como se puede ver el tipo de la variable "i" no es necesario declararlo en este caso, y es un tradicional for que imprimi 10 "Hola "[y el numero que toma la variable "i"], la cual va del 0 al 9.


Recorriendo String con For
Antes de seguir con el ejemplo, en Go los String son un tipo de dato nativo a diferencia de C (Wiii!!)

package main
import "fmt"
func main(){
    s := "diego sarmentero";
    for _, c := range(s){
        fmt.Printf("%c\n", c)
    }
}

En este ejemplo también podemos ver que no es necesario declarar el tipo de la variable "s".
Y en cuanto al for, vemos que es posible utilizar una especie de "for-each" en Go, pero es un tanto distinto a lo que uno podría estar acostumbrado, para empezar vemos que tenemos "_, c" esto es porque en la primer posición se estaría obteniendo el valor de cada iteración (la tipica variable i), la cual se recibe con "_" indicando que es ignorado y en la segunda posición se obtiene una variable de tipo carácter, con el valor correspondiente a la posición que se esta leyendo en el string.
La función range() (no les suena de Python?), especifica la cantidad de elementos por la que se iterara.

Recibiendo Argumentos
El siguiente programa utiliza el paquete "flag" para leer los argumentos que recibe el programa al ser ejecutado, luego con un for recorre los argumentos utilizando como tope el valor obtenido por la función "flag.NArg()" la cual devuelve el número de la cantidad de argumentos ingresados, y va concatenando en un string cada uno de estos argumentos separados por un espacio y luego imprime ese string en pantalla (en este ejemplo puede verse que pueden hacerse varias importaciones, declaraciones de constantes, etc, simplemente colocando la palabra reservada y luego dentro de un parentesis todo a lo que se aplica):

package main
import(
    "os";
    "flag";
)
const(
    Space = " ";
)
func main(){
    flag.Parse();
    s := "";
    for i := 0; i < flag.NArg(); i++ {
        if i > 0 {
            s += Space
        }
        s += flag.Arg(i)
    }
    os.Stdout.WriteString(s + "\n")
}

Invocando una Función y Retornando un valor:
En este ejemplo podemos ver como se crea un array, se pasa la referencia a este array a una función, sin necesidad de explicitar el tamaño del mismo como se suele hacer en algunos casos en C, sino que dentro del método se utiliza la función len() para calcular el tamaño del mismo (la típica: sizeof(array)/sizeof(array[0])), entonces en la función se recorre el array, se van sumando sus valores y luego se devuelve el resultado. Cabe destacar, que la variable a retornar se define en la declaración del método mismo y al colocar el "return" no es necesario especificar ahí la variable.
Otro tema interesante es que un mismo método puede retornar mas de una variable, pero eso es un tema para el siguiente post.

package main
import "fmt"
func main(){
    var array = [4]int{1, 2, 3, 4};
    s := sum(&array);
    fmt.Printf("%d\n", s)
}
func sum(a []int) (b int){
    for i:= 0; i < len(a); i++ {
        b += a[i]
    }
    return
}

Servidor Web
Y para terminar, este es un ejemplo que vi en UbuntuLife y que queria poner para que se vea lo facil que se pueden hacer algunas cosas:
Con “Go” podemos incluso crear un servidor web en apenas muy pocas lineas de codigo:

package main
import (
"http";
"io";
)
func main() {
    //define la funcion para manejar la peticion a "/test_go"
    http.Handle("/test_go", http.HandlerFunc(RequestHandler));
    //esperar conexiones entrantes en el puerto 1234
    err := http.ListenAndServe(":1234", nil);
    //si se produce algun error:
    if err != nil {
         panic("Error: ", err.String());
    }
}
func RequestHandler(c *http.Conn, req *http.Request) {
    //recuperar e imprimir los parametros:
    str :=  "<strong>Protocol:</strong> " +
    req.Proto + "" +"<strong>Method:</strong> " +
    req.Method + "" +"<strong>User-Agent:</strong> " +
    req.UserAgent;
    //escribir la respuesta:
    io.WriteString(c, str);
}


Al ejecutarlo se creara el servidor web que quedara esperando a las peticiones entrantes.
Abre ahora un navegador y mete como URL: http://127.0.0.1:1234/test_go
De manera inmediata deberias poder ver la respuesta del server:

No comments: