Los nombres de los proyectos no reflejan los días. Sólo siguen su propia secuencia. Están ordenados de más reciente a más antiguo.
Para ordernar tipos de datos hay que implementar la interfaz de sort.Sort() que consta de tres métodos
Len() int
Less(i, j int) bool
Swap(i, j int)
Las struct
pueden contener propiedades anónimas que agregan una composición de datos.
type Point struct {
X, Y float64
}
type ColoredPoint struct {
Point
color string
}
Para construir estas estructuras se usan puros valores
color := "red"
c := geometry.ColoredPoint{ geometry.Point{1, 1}, color }
Alias para el paquete
import (
"crypto/rand"
mrand "math/rand" // alternative name mrand avoids conflict
)
Si no se usa el paquete que se importa Go marca un error. Para evitarlo se puede importar en "blanco"
import _ "image/png" // register PNG decoder
Cada vez que se invoca un método de un tipo o estructura se realiza una copia de la información. Para evitarlo se puede pasar un apuntador
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
La convención es que si hay un método que recibe un apuntador entonces todos los métodos deben recibir un apuntador. Se invoca de la siguiente manera
// La simple, haciendo uso de la transformación implícita del compilador
p.ScaleBy(2) // funciona sólo para variables
// OTRAS FORMAS
r := &Point{1, 2}
r.ScaleBy(2)
fmt.Println(*r) // "{2, 4}"
// --
p := Point{1, 2}
pptr := &p
pptr.ScaleBy(2)
fmt.Println(p) // "{2, 4}"
// --
p := Point{1, 2}
(&p).ScaleBy(2)
fmt.Println(p) // "{2, 4}"
Go no tiene en estos momentos un buen soporte de genéricos. Por ejemplo no es posible definir una estructura que tenga un valor genérico que permita hacer comparaciones con todos los operadores: ==, !=, <, > <=, >=.
La interfaz comparable
sólo opera con == y !=.
Para poder crear una estructura que pueda soportar un valor con múltiples tipos se puede declarar una interfaz.
type Valuable interface {
int | float64 | string
}
Posteriormente se usa dicha interfaz para declarar una struct
usando la misma sintaxis como en generic
.
type BinaryTree[T Valuable] struct {
value T
left,right *BinaryTree[T]
}
Si los archivos .go de una carpeta no corresponden todos al mismo package
hay errores.
Para organizarlo se pueden crear subcarpetas, cada una con archivos que declaran un package
diferente.
Si no hay un package main
no se puede ejecutar usando go run .
. Esto significa que paquetes diferentes a main sólo pueden ser librerías.
Es posible sobrecargar la representación de un tipo mediante una función, por ejemplo aquí se hace con string
func (f Farenheit) String() string {
return fmt.Sprintf("%.2f °F", f)
}
func (c Celsius) String() string {
return fmt.Sprintf("%.2f °C", c)
}
De la misma manera
func (f Farenheit) IntoCelsius() Celsius {
return Celsius( (f - 32) / 1.8000 )
}
func (k Kelvin) IntoCelsius() Celsius {
return Celsius(k - 273.15)
}
Para usar la sobrecarga
temp := Celsius(37)
conv := temp.IntoFarenheit()
convStr = conv.String()
Declarar constantes que asemejan a enum
s
type EventType string
const (
one EventType = "one"
two = "two"
three = "three"
)
type EventTypeNumber uint8
const (
oneNumber EventTypeNumber = iota
twoNumber
threeNumber
)
iota
genera autonumeración comenzando en cero.
Siguiendo https://www.mongodb.com/languages/golang y https://www.mongodb.com/blog/post/quick-start-golang--mongodb--modeling-documents-with-go-data-structures
Declaraciones de estructuras son
type nombre struct {
...
}
Los campos van dentro de la declaración indicando su tipo de datos
type person struct {
ID string
}
Las estructuras soportan anotaciones para los campos usando ``, por ejemplo para convertir a un campo JSON
type person struct {
ID string `json:"id"`
}
Declarar variables con una estructura como tipo se da de la forma
var onePerson = person{ ID: "1" }
var persons = person[]{
{ID: "1"},
{ID: "2"},
}
El paquete gin es un web framework. Opcionalmente se necesita el paquete net/http
para ciertas constantes estándares en HTTP.
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.Run("localhost:8080")
}
""" gin.Context is the most important part of Gin. It carries request details, validates and serializes JSON, and more. (Despite the similar name, this is different from Go’s built-in context package.) """
Las funciones que realizan acciones reciben un apuntador a gin.Context
.
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.Run("localhost:8080")
}
Gin también puede transformar los datos enviados en una nueva entidad a partir de la struct.
Para esto usa c.BindJSON()
func postAlbum(c *gin.Context) {
var newAlbum album
if err := c.BindJSON(&newAlbum); err != nil {
return ;
}
albums = append(albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
Se observa que cuando se envían datos vacíos la entidad se crea con datos por default.
...
{
"id": "",
"title": "",
"artist": "",
"price": 0
}
...
También que gin
envía automáticamente un error 400 si falla el parse y no se manipula la respuesta del servidor.
Una respuesta puede enviar un objeto a partir de la struct H
de gin
.
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
Remover un elemento en un slice se realiza mendiante la composición de los elementos excluyentes
for i, album := range albums {
if album.ID == id {
albums = append(albums[:i], albums[i+1:]...)
c.Status(200)
return
}
}
Go tiene manipulación de imágenes en la librería estandar mediante el paquete img.
import "img"
Para abrir una imágen es necesario primero crear un io.Reader
reader, err := os.Open(filePath)
img, s, err := image.Decode(reader)
En este caso s
es el formato de la imagen (png, jpeg, gif), img
contiene una estructura con referencia a la imagen.
Es posible cargar una librería sólo por sus efectos secundarios mediante import _
, ejemplos:
import _ "image/png"
import _ "image/jpeg"
// juntos
import (
_ "image/png"
_ "image/jpeg"
)
En este caso después de importar es posible operar con imágenes png y jpeg.
El paquete os
también permite leer archivos, aunque en este caso retorna un reader
err, reader := os.Open(filePath)
Usar defer
permite detener la ejecución de una función hasta que todas las llamadas o manipulaciones bajo ella hayan sido completadas
reader, err := os.Open(filePath)
if err != nil {
fmt.Printf("Error reading file %s: %v", filePath, err)
os.Exit(1)
}
defer reader.Close()
Para separar funcionalidades en diferentes archivos dentro del mismo paquete sólo hace falta declarar el mismo en los diferentes archivos
// main.go
package main
...
// filters.go
package main
El paquete image
tiene colores en el rango [0, 65535]. La explicación está en el blog del paquete. Para usarlo es necesario convertilo a uint8
ejemplo ru8 := uint8(r / 0x101)
.
Para escribir una imagen a archivo es necesario utilizar un descriptor y un codificador dependiendo del tipo de imagen
if imgFormat == "png" {
saveErr := png.Encode(writer, img)
if saveErr != nil {
writer.Close()
return false;
}
}
El paquete io/ioutil
soporta carga de archivos
import "io/ioutil"
func main() {
...
data, err := ioutil.ReadFile(path)
}
data
es un arreglo de byte
, para convertirlo en string
...
dataString := string(data)
...
El paquete os
tiene un slice
, Args
, que almacena los argumentos con que el programa fue invocado
import (
"fmt"
"os"
)
...
for index, arg := range os.Args {
fmt.Println(index, arg);
}
El paquete strconv
contiene funciones para hacer conversiones de strings
// val == 0, err != nil
val, err := strconv.Atoi("x")
// val == 10, err == nil
val, err := strconv.Atoi("10")
Para hacer un join the strings se puede usar el paquete strings
strings.Join(os.Args[1:], " ")
El estilo recomendado para nombrar en Go es usar camelCase
para los identificadores, excepto los que son de acceso público, que utilizan PascalCase
.
Se pueden declarar constantes usando const
. Sólo pueden ser number
, string
o boolean