Hola mundo en Go

1

Introducción al Curso de Golang

2

¿Qué es, por qué y quienes utilizan Go?

3

Instalar Go en Linux

4

Instalar Go en Mac

5

Instalar Go en Windows

6

Nuestras primeras líneas de código con Go

Variables, funciones y documentación

7

Variables, constantes y zero values

8

Operadores aritméticos

9

Tipos de datos primitivos

10

Paquete fmt: algo más que imprimir en consola

11

Uso de funciones

12

Go doc: La forma de ver documentación

Estructuras de control de flujo y condicionales

13

El poder de los ciclos en Golang: for, for while y for forever

14

Operadores lógicos y de comparación

15

El condicional if

16

Múltiple condiciones anidadas con Switch

17

El uso de los keywords defer, break y continue

Estructuras de datos básicas

18

Arrays y Slices

19

Recorrido de Slices con Range

20

Llave valor con Maps

21

Structs: La forma de hacer clases en Go

22

Modificadores de acceso en funciones y Structs

Métodos e interfaces

23

Structs y Punteros

24

Stringers: personalizar el output de Structs

25

Interfaces y listas de interfaces

Concurrencia y Channels

26

¿Qué es la concurrencia?

27

Primer contacto con las Goroutines

28

Channels: La forma de organizar las goroutines

29

Range, Close y Select en channels

Manejo de paquetes y Go Modules

30

Go get: El manejador de paquetes

31

Go modules: Ir más allá del GoPath con Echo

32

Modificando módulos con Go

Despedida del curso

33

Despedida

Bonus

34

Cheat Sheet Go

35

Librerías para desarrollo web con Go

36

Data Science con Go

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Interfaces y listas de interfaces

25/36
Recursos

Aportes 34

Preguntas 4

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

Vale aclara algo:

las funciones en Go se definen de la siguiente manera:

func  nameFunc() {
	// body de la función
}

El nombre de las funciones no se pueden repetir en un mismos paquete, pero que esta pasando con las func area que se definieron dos veces en esta clase?

Lo que esta sucediendo es que no son simplemente funciones, en Go se les conoce como Methods. Un método es una función con un argumento de receptor especial. que debe de ser de tipo struct o interface y se definen de la siguiente manera:

func (receiver type)  nameFunc() {
	// body del metodo
}

Una buena practica es nombrar a nuestro receptor con la primera letra del struct o interface a la que estamos haciendo referencia, por ejemplo:

type cuadrado struct {
	lado float32
}

func (c cuadrado) area() float32 {
	return c.lado * c.lado
}

Reto

package main

import (
	"fmt"
	"math"
	"reflect"
)

type figure2D interface {
	getArea() float64
}

type square struct {
	base float64
}

type rectangle struct {
	high  float64
	width float64
}

type trapezoid struct {
	baseA float64
	baseB float64
	high  float64
}

type circle struct {
	radio float64
}

func (s square) getArea() float64 {
	return s.base * s.base
}

func (r rectangle) getArea() float64 {
	return r.high * r.width
}

func (t trapezoid) getArea() float64 {
	return ((t.baseA + t.baseB) / 2) * t.high
}

func (c circle) getArea() float64 {
	return math.Pi * math.Pow(c.radio, 2)
}

func calculateArea(f figure2D) {
	fmt.Printf("Area of %s: %.2f\n", reflect.TypeOf(f).Name(), f.getArea())
}

func main() {
	mySquare := square{base: 5}
	myRectangle := rectangle{width: 4, high: 5}
	myTrapezoid := trapezoid{baseA: 18, baseB: 10, high: 5}
	myCircle := circle{radio: 4}
	calculateArea(mySquare)
	calculateArea(myRectangle)
	calculateArea(myTrapezoid)
	calculateArea(myCircle)
}
  • Si los structs que tenemos en el código tienen métodos que hacen algo en común (Cálculos, obtener data, etc), es posible ejecutar éstos métodos usando una interfaz, de esta forma evitamos hacer código por cada struct.

Una aclaracion sobre el doble corchete

myInterface := []{}{"hola", 12, true}

https://stackoverflow.com/questions/57149795/what-does-the-double-curly-brace-mean-in-interface/57150132

Me gusta mucho la forma de declarar las listas de interfaces:

package main

import "fmt"

func main() {
	myInterface := []interface{}{"Hola", 121, 4.90}
	fmt.Println(myInterface...)
}

Mas documentado aquí.

Salio con fritas…

Este es el principal

package main

import (
	cua "curso_golang_basico/src/12Interfaces/pkgcuadrado"
	inter "curso_golang_basico/src/12Interfaces/pkginterfaces"
	rec "curso_golang_basico/src/12Interfaces/pkgrectangulo"
	"fmt"
)

func main() {

	var micuadrado cua.Cuadrado
	micuadrado.CreaLado(4)

	var mirec rec.Rectangulo
	mirec.CreaRec(8, 3)

	fmt.Println(micuadrado)
	fmt.Println(mirec)

	// Sin interfaces
	fmt.Println("\nSin interfaces: ")
	fmt.Println("Area cuadrado: ", micuadrado.Area())
	fmt.Println("Area rectangulo: ", mirec.Area())

	// Con interfaces
	fmt.Println("\nCon interfaces")
	inter.Calcular(micuadrado)
	inter.Calcular(mirec)

}

Este es el package cuadrado (un subdir dentro del principal)

package pkgcuadrado

import "fmt"

type Cuadrado struct {
	lado int
}

func (c *Cuadrado) CreaLado(l int) {
	c.lado = l
}

func (c Cuadrado) String() string {
	return fmt.Sprintf("Cuadrado de lado = %d", c.lado)
}

func (c Cuadrado) Area() int {
	return c.lado * c.lado
}

Este es ahora el package rectangulo

package pkgrectangulo

import "fmt"

type Rectangulo struct {
	largo int
	ancho int
}

func (r *Rectangulo) CreaRec(l, a int) {
	r.largo = l
	r.ancho = a
}

func (r Rectangulo) String() string {
	return fmt.Sprintf("Rectangulo de largo = %d y ancho = %d", r.largo, r.ancho)
}

func (r Rectangulo) Area() int {
	return r.ancho * r.largo
}

Y finalmente poniendome creativo un package para las interfaces…

package pkginterfaces

import "fmt"

type figuras2D interface {
	Area() int
}

func Calcular(f figuras2D) {
	fmt.Println("Area: ", f.Area())
}

Y lo mejor de todo es que anda! 😃

Reto 🥳

//Main
package main

import (
	pk "curso_golang_platzi/src/mypackage"
	f "fmt"
)

func main() {

	myCuadrado := pk.Cuadrado{Base: 4}
	f.Println(myCuadrado)
	pk.Calcular(myCuadrado)

	myRectangulo := pk.Rectangulo{Base: 2, Altura: 4}
	f.Println(myRectangulo)
	pk.Calcular(myRectangulo)

	myCirculo := pk.Circulo{Radio: 5}
	f.Println(myCirculo)
	pk.Calcular(myCirculo)

}
//mypackage
package mypackage

import "fmt"

type Figuras2D interface {
	area() float64
}

type Cuadrado struct {
	Base float64
}

type Rectangulo struct {
	Base   float64
	Altura float64
}

type Circulo struct {
	Radio float64
}

func (c Cuadrado) area() float64 {
	return c.Base * c.Base
}

func (r Rectangulo) area() float64 {
	return r.Base * r.Altura
}

func (ci Circulo) area() float64 {
	return  (ci.Radio * ci.Radio) * 3.1415
}

func Calcular(f Figuras2D) {
	fmt.Println("Área:", f.area())
}


Si se les dificulto un poco el funcionamiento de las interfaces en Golang (ya que en Java o Python son más como contratos, en donde cumplimos el implementar una función en una clase), espero que mi explicación les ayude

Tomo a las interfaces más como herramientas para hacer parámetros de Structs en funciones universales, me explico:

Creamos esta función para calcular el area de cuadrado

func (c cuadrado) area() float64{
	return c.base * c.base
}

Normalmente tendríamos que invocar el método del struct cada que queramos usar la función

myCuadrado := cuadrado{base:2}
myCuadrado.area()

Pero gracias a las interfaces, ahora podemos pasar el Struct myCuadrado como parametro y reutilizar una misma funcion en multiples Structs

//Creamos un Struct triangulo
type triangulo struct{
	base float64
	altura float64
}

//Instanciamos el struct triangulo
myTriangulo := triangulo{base: 2, altura: 4}

//Creamos la interface
type figuraGeometrica2d interface{
	area() float64
}

//Ahora tenemos una función que toma como parametro Structs
func calcularArea(f figuraGeometrica2d){
	fmt.Println("El area de tu figura es de: ", f.area)
}

Y ahora, gracias a la interface, podemos pasar a todo Struct que tenga un método area() como parametro de la funcion calcularArea

calcularArea(myCuadrado)
calcularArea(myTriangulo)

Si se les dificultó entender el concepto o uso de interface, espero haberles ayudado (:

Código para usar un poder especial de diferentes formas con diferentes pokemon. El resultado: la cantidad de poder que aumenta el pokemon.

package main

import "fmt"

type pokemonPwrs interface {
	usePwr() int
}

type myElecPokemon struct {
	name string
	volts int
	level int
}

type myFirePokemon struct {
	name string
	flames int
	level int
}

func (fPoke myFirePokemon) usePwr() int {
	return fPoke.flames * fPoke.level
}

func (ePoke myElecPokemon) usePwr() int {
	return ePoke.volts * ePoke.level
}

func  useSpecialPwrs(p pokemonPwrs) {
	fmt.Printf("Power: %v \n", p.usePwr())
}

func main() {
	var pikachu = myElecPokemon{name: "Pikachu", volts: 10, level: 3}
	var litten = myFirePokemon{name: "Litten", flames: 25, level:5}
	useSpecialPwrs(pikachu)
	useSpecialPwrs(litten)
}

figures/figures.go

package figures

import "fmt"

type figuras2D interface {
	area() float64
}

type Cuadrado struct {
	base float64
}

type Rectangulo struct {
	base   float64
	altura float64
}

func (c Cuadrado) area() float64 {
	return c.base * c.base
}

func (r Rectangulo) area() float64 {
	return r.altura * r.base
}

func Calcular(f figuras2D) {
	fmt.Println("Area:", f.area())
}

//setters & getters
func (c *Cuadrado) SetCuadradoBase(base float64) {
	c.base = base
}

func (c Cuadrado) GetCuadradoBase() float64 {
	return c.base
}

func (r *Rectangulo) SetRectanguloBase(base float64) {
	r.base = base
}

func (r Rectangulo) GetRectanguloBase() float64 {
	return r.base
}

func (r *Rectangulo) SetRectanguloAltura(altura float64) {
	r.altura = altura
}

func (r Rectangulo) GetRectanguloAltura() float64 {
	return r.altura
}

main.go

import (
	"golang/fundamentos/figures"
)
func main() {
	mycuadrado := figures.Cuadrado{}
	mycuadrado.SetCuadradoBase(4)

	myrectangulo := figures.Rectangulo{}
	myrectangulo.SetRectanguloAltura(10)
	myrectangulo.SetRectanguloBase(2)

	figures.Calcular(mycuadrado)
	figures.Calcular(myrectangulo)

}

Acá encuentran las clases 23, 24, 25
repo-cool-go

Recorriendo una lista de interfaces

interfaceLis := []interface{}{"Hello world", 4.5, 5, true}
	fmt.Println(interfaceLis)

	for i, v := range interfaceLis {
		fmt.Println(i, v)
	}

Me tomo un tiempo entender q es la lista de interfaces, este stackoverflow explica bien por q la repeticion de {}{}
https://stackoverflow.com/questions/57149795/what-does-the-double-curly-brace-mean-in-interface/57150132

Este feature de Go, te permite crear un slice indicando q INTERFACE pertenecen todos los items creados:

  // Slice de objetos de la interfaz figuras2D
	figuras := []figuras2D{cuadrado{base: 2}, rectangulo{base: 2, altura: 4}}
	for _, figura := range figuras {
		fmt.Println(figura)
		calcular(figura)
	}

Y al intentar colocar un objeto q no tiene la implementacion de esa interfaz, pues el editor y al correr te indicaran q no implementa lo q indica la interfaz.
Ese feature realmente me gusto

// Agregando un STRING en el slice
	figuras := []figuras2D{cuadrado{base: 2}, rectangulo{base: 2, altura: 4}, "invalid object"}

// Al ejecutarlo
PS C:\git\test-go> go run .\src\interfacesListas.go
# command-line-arguments
src\interfacesListas.go:55:76: cannot use "invalid object" (constant of type string) as type figuras2D in array or slice literal:
        string does not implement figuras2D (missing area method)

Mi solución al reto:

Paquete:

package mypackage

import (
	"fmt"
)
// trapecio para reto

type Trapecio struct {
	Altura     float64
	Base_menor float64
	Base_mayor float64
	//area
	sum   float64
	mitad float64
}

// sacar area para el trapecio
//-declaración de variable para función
var T Trapecio

func (T *Trapecio) area() float64 {
	T.sum = T.Base_menor + T.Base_mayor
	T.mitad = T.sum / 2
	return T.mitad * T.Altura
}

//-striger para trapecio
func (T Trapecio) string() string {
	return fmt.Sprintf("El trapecio con altura %v, base menor %v y base mayor %v tiene area ", T.Altura, T.Base_menor, T.Base_mayor)
}
// circulo para el reto

type Circulo struct {
	Diametro float64
	//area
	radio          float64
	cuadrado_radio float64
	pi             float64
}

// sacar area al circulo
//-declaración de variable usada en la función
var C Circulo

func (C *Circulo) area() float64 {
	C.pi = 3.144142
	C.radio = C.Diametro / 2
	C.cuadrado_radio = C.radio * C.radio
	return C.pi * C.cuadrado_radio
}

//-stringer para circulo
func (C Circulo) string() string {
	return fmt.Sprintf("El circulo de diametro %v tiene area ", C.Diametro)
}
type figuras interface {
	area() float64
	string() string
}

func Cal(f figuras) {
	fmt.Print(f.string())
	fmt.Println(f.area())
}

Main:

package main

import (
	"golang/src/mypackage"
)

func main() {
	my_trapecio := mypackage.Trapecio{
		Base_menor: 3.5,
		Base_mayor: 9.5,
		Altura:     4,
	}
	my_circulo := mypackage.Circulo{
		Diametro: 4,
	}

	mypackage.Cal(&my_trapecio)
	mypackage.Cal(&my_circulo)
}

Me gustaría mucho una retroalimentación del profesor o una corrección si lo amerita.

Aproveche de implementar String de tal forma que muestre el tipo de figura.

package geometry

import (
	"fmt"
	"math"
)

type Rectangle struct {
	Base, Height float64
}

func (rectangle Rectangle) Area() float64 {
	return rectangle.Base * rectangle.Height
}

func (rectangle Rectangle) String() string {
	return fmt.Sprintf("Rectangle{Base: %.2f, Height: %.2f}", rectangle.Base, rectangle.Height)
}

func (rectangle Rectangle) Diagonal() float64 {
	return math.Sqrt(math.Pow(rectangle.Base, 2) + math.Pow(rectangle.Height, 2))
}

En lenguajes tipicamente orientados a objetos como Java, la implementación de una interface se hace de manera explicita.

MyClase implements MyInterface

En Go esta implementación es implícita

package main

import "fmt"

type I interface {
	M()
}

type T struct {
	S string
}

// El método M indica que el type T implementa la interface I,
// pero no se requiere una declaración explícita
func (t T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I = T{"hello"}
	i.M()
}


https://go.dev/tour/methods/10

Mi solución
Mi Package main:

package main

import (
	pb "curso_golang_go/Intefarces_Listas_de_interfaces/reto/metodos_y_structs_Publicos"
	"fmt"
)

type areas interface {
	Area1() float64
}

func calcularPrivado(f areas) {
	fmt.Println("El area es:", f.Area1())
}
func main() {
	var cuadradoPu pb.Cuadrado
	var rectanguloPu pb.Rectangulo
	var circuloPu pb.Circulo

	cuadradoPu.Base = 2
	rectanguloPu.Altura = 3
	rectanguloPu.Base = 3
	circuloPu.Pi = 3.14
	circuloPu.Radio = 4

	calcularPrivado(cuadradoPu)
	calcularPrivado(circuloPu)
	calcularPrivado(rectanguloPu)
}

Mi package Import:

package publicos

type Circulo struct {
	Pi    float64
	Radio float64
}

type Rectangulo struct {
	Base   float64
	Altura float64
}

type Cuadrado struct {
	Base float64
}

func (c Cuadrado) Area1() float64 {
	return c.Base * c.Base
}

func (r Rectangulo) Area1() float64 {
	return r.Altura * r.Base
}

func (ci Circulo) Area1() float64 {
	return ci.Pi * (ci.Radio * ci.Radio)
}

NOTA: Deje la Interfaz como privada pues cuando la dejaba publica me arrojaba error ¿Alguien sabe porque ?

:3
Brutal.

Mi solucion al reto:
En el Package:

//INTERFAZ
type Figure interface {
	Area() float64
}

//CLASES PARA LA INTERFAZ
type Rectangulo struct {
	Base   float64
	Altura float64
}

type Trapecio struct {
	Base      float64
	BaseMayor float64
	Altura    float64
}

type Circulo struct {
	Radio float64
}

//FUNCIONES DE LAS CLASES PARA LA INTERFAZ
func (r Rectangulo) Area() float64 {
	return r.Base * r.Altura
}

func (t Trapecio) Area() float64 {
	return ((t.Base + t.BaseMayor) * t.Altura) / 2
}

func (c Circulo) Area() float64 {
	const PI float64 = 3.14
	return PI * (math.Pow(c.Radio, 2))
}

//Funcion de la interfaz
func Calculate(f Figure) {
	fmt.Println("El area es: ", f.Area())
}

Clase Main:

//EJECUCION DE LA INTERFAZ EN MAIN
	myRectangulo := pk.Rectangulo{Base: 10, Altura: 5}
	myTrapecio := pk.Trapecio{Base: 5, BaseMayor: 10, Altura: 4}
	myCirculo := pk.Circulo{Radio: 7}

	pk.Calculate(myRectangulo)
	pk.Calculate(myTrapecio)
	pk.Calculate(myCirculo)

Podemos agregar interfaces a una interfaz:

// [...]
func main() {
   typeInte      := []interface{}{1,2,3}
   typeStri      := []interface{}{"a", "b", "c"}
   typeBool      := []interface{}{true, false}

   myInterface   := []interface{}{typeBool, typeStri, typeInte}
   fmt.Println(myInterface)

}

Holas Osmandi, seria chevere que pudieras agregar a este video la importancia de las interfaces, teniendo en cuenta que hay personas que vienen sin saber POO.

Saludos.

Otra forma de imprimir el area de cada Struct:

fmt.Println(figuras2D.area(myCuadrado))
fmt.Println(figuras2D.area(myRectangulo))

Este concepto es extremadamente poderoso para implementar. Es un poco distinto a Python y me encanta como dos approaches distintos muestran sus potencialidades. En este sentido, cada struct con sus funciones debería ir en un archivo por separado verdad? Para mantener el orden

Uff!! OOP en Go 💙

Para quienes deseen ponerse un norte en este tema
Medium - Programación Orientada a Objetos

🤯

aqui les dejo mi aporte 😄

<
// Main

package main

import (
	pki "curso_golang_platzi/src/packageinterfaces"
	"fmt"
)

func main() {

	// Preguntar al ususario a que figura quiere calcular su area
	fmt.Println("Actualmente puedo calcular el area de las siguientes figuras")
	fmt.Println("Cuadrado, Rectangulo, Circulo, Triangulo")
	fmt.Println("Ingrese el nombre de la figura:")
	var figura string
	fmt.Scanf("%s", &figura)

	if figura == "Cuadrado" {
		fmt.Println("Ingrese el valor de la base:")
		var base float64
		fmt.Scanf("%f", &base)
		myCuadrado := pki.Cudrado{Base: base}
		pki.CalculaArea(myCuadrado)
	} else if figura == "Rectangulo" {
		fmt.Println("Ingrese el valor de la base:")
		var base float64
		fmt.Scanf("%f", &base)
		fmt.Println("Ingrese el valor de la altura:")
		var altura float64
		fmt.Scanf("%f", &altura)
		myRectangulo := pki.Rectangulo{Base: base, Altura: altura}
		pki.CalculaArea(myRectangulo)
	} else if figura == "Circulo" {
		fmt.Println("Ingrese el valor del radio:")
		var radio float64
		fmt.Scanf("%f", &radio)
		myCirculo := pki.Circulo{Radio: radio}
		pki.CalculaArea(myCirculo)
	} else if figura == "Triangulo" {
		fmt.Println("Ingrese el valor de la base:")
		var base float64
		fmt.Scanf("%f", &base)
		fmt.Println("Ingrese el valor de la altura:")
		var altura float64
		fmt.Scanf("%f", &altura)
		myTriangulo := pki.Triangulo{Base: base, Altura: altura}
		pki.CalculaArea(myTriangulo)
	} else {
		fmt.Println("Figura no valida porfavor vuelva a intentarlo")
		fmt.Println("**********************************************")
		main()
	}
}

// Package

package packageinterfaces

import (
	"fmt"
)

type Figuras2D interface {
	Area() float64
}

type Cudrado struct {
	Base float64
}

type Rectangulo struct {
	Base   float64
	Altura float64
}

type Circulo struct {
	Radio float64
}

type Triangulo struct {
	Base   float64
	Altura float64
}

func (c Cudrado) Area() float64 {
	return c.Base * c.Base
}

func (r Rectangulo) Area() float64 {
	return r.Base * r.Altura
}

func (c Circulo) Area() float64 {
	return 3.14 * c.Radio
}

func (t Triangulo) Area() float64 {
	return t.Base * t.Altura / 2
}

func CalculaArea(f Figuras2D) {
	fmt.Println("Area:", f.Area())
}



> 

Algo que no se menciona en el curso y puede generar duda es como la función calculate sabe que los structs que pasamos están implementando la interfaz que estamos esperando. Esto pasa porque GO de forma implícita implementa la interfaz cuando un struct tiene todos los métodos que esa interfaz necesita.

Adicional recuerden que en ese ejemplo se aplican algunos principios SOLID como: Interface segregation principle, Liskov substitution y Dependency inversion principle.

Recordando Java y ocultando los atributos del struct me puse a jugar con lo siguiente:

package main

import (
	cua "curso_golang_basico/src/12Interfaces/pkgcuadrado"
	"fmt"
)

func main() {

	var micuadrado cua.Cuadrado
	micuadrado.CreaLado(4)

	fmt.Println("Imprimo micuadrado: ", micuadrado)
}

Y en el package…

package pkgcuadrado

import "fmt"

type Cuadrado struct {
	lado int
}

func (c *Cuadrado) CreaLado(l int) {
	c.lado = l
}

func (c Cuadrado) String() string {
	return fmt.Sprintf("Cuadrado de lado = %d", c.lado)
}

De esta manera no hago publico informacion que no estaria bueno exponer 😃

Hola, desarrollé esta solución para ejecutar la función que tienen en comun un conjunto de instancias de los struct que implementen una interface

	// llamar la funcion calcular para cada elemento de
	// un slice del tipo figuras2D
	myInterfaceList := []figuras2D{myCuadrado, myRectangulo}
	for _, value := range myInterfaceList {
		calcular(value)
	}

Reto:
main.go

package main

import (
	fg "curso-golang/src/18.Interfaces/figuras"
	"fmt"
)

type figuras2D interface {
	Area() float64
}

func calcular(f figuras2D) {
	fmt.Printf("Area: %v\n", f.Area())
}

func main() {
	miCuadrado := fg.NewCuadrado(2)
	miRectangulo := fg.NewRectangulo(2, 4)
	miCirculo := fg.NewCirculo(3.2)
	miTriangulo := fg.NewTriangulo(7.8, 2.9)

	calcular(miCuadrado)
	calcular(miRectangulo)
	calcular(miCirculo)
	calcular(miTriangulo)
}

cuadrado.go

package figuras

type cuadrado struct {
	base float64
}

func NewCuadrado(bs float64) cuadrado {
	return cuadrado{base: bs}
}

func (c cuadrado) Area() float64 {
	return c.base * c.base
}

rectangulo.go

package figuras

type rectangulo struct {
	base   float64
	altura float64
}

func NewRectangulo(bs, alt float64) rectangulo {
	return rectangulo{base: bs, altura: alt}
}

func (r rectangulo) Area() float64 {
	return r.altura * r.base
}

circulo.go

package figuras

import "math"

type circulo struct {
	radio float64
}

func NewCirculo(rd float64) circulo {
	return circulo{radio: rd}
}

func (c circulo) Area() float64 {
	return math.Pi * c.radio * c.radio
}

triangulo.go

package figuras

type triangulo struct {
	base   float64
	altura float64
}

func NewTriangulo(bs, alt float64) triangulo {
	return triangulo{base: bs, altura: alt}
}

func (t triangulo) Area() float64 {
	return t.base * t.altura / 2
}
package main

import "fmt"

type cuadrado struct {
	base float64
}

type figuras2d interface {
	area() float64
}

type rectangulo struct {
	base   float64
	altura float64
}

func (c cuadrado) area() float64 {
	return c.base * c.base
}

func calcular(f figuras2d) {
	fmt.Println("Area:", f.area())
}

func (r rectangulo) area() float64 {
	return r.base * r.altura
}

func main() {
	myCuadrado := cuadrado{base: 2}
	myRectangulo := rectangulo{base: 2, altura: 4}

	calcular(myCuadrado)
	calcular(myRectangulo)

	// Lista de interfaces
	myInterface := []interface{}{"Hola", 12, 4.90}
	fmt.Println(myInterface...)
}

triangle.go

package figures

import "fmt"

type Triangle struct {
	base float64
	hight float64
}

func NewTriangle(base, hight float64) Triangle {
	return Triangle{base, hight}
}

func (f Triangle) GetArea() float64 {
	return  f.base * f.hight / 2
}

func (f Triangle) String() string  {
	return fmt.Sprintf("{ base:%.1f, heght:%.1f, area:%.1f }", f.base, f.hight, f.GetArea())
} 

square.go

package figures

import "fmt"

type Square struct {
	base float64
}

func NewSquare(base float64) Square {
	return Square{base}
}

func (f Square) GetArea() float64 {
	return  f.base + f.base
}

func (f Square) String() string  {
	return fmt.Sprintf("{ base:%.1f, area:%.1f }", f.base, f.GetArea())
} 

circle.go

package figures

import (
	"fmt"
	"math"
)

type Circle struct {
	radio float64
}

func NewCircle(radio float64) Circle {
	return Circle{radio}
}

func (f Circle) GetArea() float64 {
	return  math.Pi * f.radio * f.radio
}

func (f Circle) String() string  {
	return fmt.Sprintf("{ radio:%.1f, area:%.1f }", f.radio, f.GetArea())
} 

rectangle.go

package figures

import "fmt"

type Rectangle struct {
	base float64
	hight float64
}

func NewRectangle(base, hight float64) Rectangle {
	return Rectangle{base, hight}
}

func (f Rectangle) GetArea() float64 {
	return  f.base + f.hight
}

func (f Rectangle) String() string  {
	return fmt.Sprintf("{ base:%.1f, heght:%.1f, area:%.1f }", f.base, f.hight, f.GetArea())
} 

CODIGO

package main

import (
	"fmt"
	"golang-base/practices/src/figures"
	"reflect"
)

type figuras2D interface {
	GetArea() float64
}

func  calcular(f figuras2D) float64 {
	return f.GetArea()
}

func main() {
	// Creacion de figuras
	myCircle := figures.NewCircle(10)
	myRectangle := figures.NewRectangle(40,20)
	mySquare := figures.NewSquare(30)
	myTrapeze := figures.NewTrapeze(60,40,10)
	myTriangle := figures.NewTriangle(40,30)

	// Lista de interfaces
	myInterface := []interface{}{myCircle, myRectangle, mySquare, myTrapeze, myTriangle}
	fmt.Println("=======  F I G U R A S  =======")
	for _, v := range myInterface {
		fmt.Printf("%s ==> %v \n", reflect.TypeOf(v), v)
	}

	// Calculo del area de las figuras
	fmt.Println("\n=======  A R E A S  =======")
	fmt.Printf("Rectangle-Area = %.2f \n", calcular(myRectangle))
	fmt.Printf("Circle-Area = %.2f \n", calcular(myCircle))
	fmt.Printf("Square-Area = %.2f \n", calcular(mySquare))
	fmt.Printf("Trapeze-Area = %.2f \n", calcular(myTrapeze))
	fmt.Printf("Triangle-Area = %.2f \n", calcular(myTriangle))
} 

EJECUCION

=======  F I G U R A S  =======
figures.Circle ==> { radio:10.0, area:314.2 } 
figures.Rectangle ==> { base:40.0, heght:20.0, area:60.0 } 
figures.Square ==> { base:30.0, area:60.0 } 
figures.Trapeze ==> { base:60.0, top:40.0, heght:10.0, area:500.0 } 
figures.Triangle ==> { base:40.0, heght:30.0, area:600.0 } 

=======  A R E A S  =======
Rectangle-Area = 60.00 
Circle-Area = 314.16 
Square-Area = 60.00 
Trapeze-Area = 500.00 
Triangle-Area = 600.00