Saltar al contenido principal

OOP

En golang no hay OOP, pero se puede emular, lo veremos…

Estructura (struct)

Es un objeto de datos que tiene diferentes campos, similar a una clase, pero no lo es, es una representación de un tipo de dato.

type Persona struct {
Id int
Nombre string
Correo string
Edad int
}

Las estucturas deben comenzar con mayusculas si quieren ser exportadas a otro modulo de go.

Los nombres de los campos tambien van en mayusculas si son publicos.

Para crear una instancia del struct:

persona := Persona{
Id: 1,
Nombre: "Jose",
Correo: "jose.cardozo@silstech.com.ar",
Edad: 28
}

fmt.Println(persona)
fmt.Println(reflect.TypeOf(persona))

// {1 Jose jose.cardozo@silstech.com.ar 28}
// main.Persona --> Este es el tipo del struct

Otra forma de declarar structs

Usando el constructor new

p := new(Persona)

fmt.Println(reflect.TypeOf(p))

Output:

*main.Persona

Como vemos la diferencia de la forma anterior es que en esta forma nos almacena en la variable el puntero a memoria de la estructura.

Si queremos definir parametros de la estructura:

p.Id = 2
p.Nombre = "Juan Perez"
p.Correo = "juan.perez@silstech.com.ar"
p.Edad = 32

fmt.Println(p)
fmt.Printf("%+v \n", p)

Output:

&{2 Juan Perez juan.perez@silstech.com.ar 32}
&{Id:2 Nombre:Juan Perez Correo:juan.perez@silstech.com.ar Edad:32}

Esta forma es usada frecuentemente por los ORM para modificar registros en la db.

Estructuras anidadas (o Pseudo-Herencia)

Esta forma permite anidad structs dentro de otra, para lo cual necesito declarar dentro del struct padre la estructura correspondiente al parametro el cual quiero anidar.

Supongamos que tenemos los siguientes structs.

type Categoria struct {
Id int
Nombre string
Slug string
}

type Producto struct {
Id int
Nombre string
Slug string
Precio int
Categoria Categoria
}

Declaramos una estructura de tipo categoria y luego implementamos la anidación declarando Categoria explicitamente en una instancia del tipo producto.

categoria := Categoria{Id: 1, Nombre: "Categoria 1", Slug: "categoria-1"}

producto := Producto{Id: 1, Nombre: "Mesa de computador", Slug: "mesa-de-computador", Precio: 1234, Categoria: categoria}
fmt.Printf("%+v \n", producto)

Output:

{
Id:1
Nombre:Mesa de computador
Slug:mesa-de-computador
Precio:1234
Categoria: {
Id:1
Nombre: Categoria 1
Slug: categoria-1
}
}

Nota: No es un JSON, es un output de terminal formateado a conveniencia.

Interfaces

Una interfaz en golang sirve para definir metodos implicitos en un struct la cual debe implementar y también sirve para generar una especie de polimorfismo.

Supongamos tenemos un struct Estructura la cual no tiene definido ninguna propiedad ni métodos la cual solo nos sirve para instanciar una estructura de tipo Estructura y usarla para definir metodos relacionados a la misma (como una especie de abstract class).

type Estructura struct {}

Ahora a continuacion definimos metodos relacionados a esa struct.

func (*Estructura) miFuncion() string {
return "texto desde mi función"
}

func (*Estructura) Calculo(n1 int, n2 int) int {
return n1 + n2
}

Ahora la variable e tiene disponible para implementar los metodos miFuncion y Calculo

e := Estructura{}
fmt.Println(e.miFuncion())
fmt.Println(e.Calculo(2, 2))

Output:

texto desde mi función
4

Ahora podemos lograr una especie de polimorfismo definiendo una interfaz con la palabra reservada interface y en la cual declaramos ambos metodos anteriores con sus parametros.

type EstructuraInterface interface {
miFuncion() string
Calculo(n1 int, n2 int) int
}

Para implementar la interfaz utilizamos el metodo siguiente:

func ImplementarInterface(es EstructuraInterface) {
fmt.Println(es.miFuncion())
fmt.Println(es.Calculo(2, 2))
}

e := Estructura{}

ImplementarInterface(&e) // Debemos siempre al usar interfaces pasar el puntero de memoria
texto desde mi función
4

Si ahora quiero implementar la interfaz para un struct de tipo Persona obtengo un error ya que no tiene implementado los metodos miFuncion y Calculo.

person := Persona{
Id: 1,
Nombre: "Jose",
Correo: "jose.cardozo@silstech.com.ar",
Edad: 28,
}

ImplementarInterface(&person) // Error - ImplementarInterface: missing method Calculo

Entonces implementamos el metodo como en el caso de Estructura para la struct Persona

func (*Persona) Calculo(n1 int, n2 int) int {
return n1 + n2
}

func (*Persona) miFuncion() string {
return "texto desde mi función"
}

ImplementarInterface(&person) // Ya no tira error

Output:

texto desde mi función
4

De esta forma presentamos un uso polimorfico mediante la interfaz EstructuraInterface