No tienes acceso a esta clase

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

Interfaces y listas de interfaces

25/36
Recursos

¿Qué son las interfaces en Go y por qué son útiles?

Las interfaces en Go son un concepto avanzado y poderoso que simplifica la manera en que trabajamos con métodos comunes aplicables a múltiples tipos o structs. Aunque la implementación puede parecer complicada al principio, Go lo hace más accesible. Una interfaz en Go, básicamente, permite compartir diferentes métodos, actuando como un único punto de entrada para métodos comunes aplicables a distintos tipos de datos.

Implementación básica de interfaces

En Go, para implementar interfaces, seguimos una serie de pasos:

  1. Definición de la estructura (struct):

    type Cuadrado struct {
        base float64
    }
    
    type Rectangulo struct {
        base, altura float64
    }
    
  2. Métodos para operaciones específicas: Definimos métodos para calcular el área de cada figura.

    func (c Cuadrado) area() float64 {
        return c.base * c.base
    }
    
    func (r Rectangulo) area() float64 {
        return r.base * r.altura
    }
    
  3. Definición de la interfaz: Aquí centralizamos el método común que han de implementar los structs.

    type figura2D interface {
        area() float64
    }
    
  4. Implementación de una función para cálculo genérico:

    func calcular(f figura2D) {
        fmt.Println("Área:", f.area())
    }
    

¿Cómo ejecutar el cálculo con interfaces?

En un contexto donde tenemos múltiples structs que comparten un método común, el uso de interfaces resulta beneficioso para optimizar el código. Mediante la función calcular, se puede instanciar cualquier figura que implemente la interfaz y calcular su área.

miCuadrado := Cuadrado{base: 2}
miRectangulo := Rectangulo{base: 2, altura: 4}

calcular(miCuadrado)
calcular(miRectangulo)

Al ejecutar el código anterior, obtendremos el área de cada figura en la consola, lo que muestra cómo la interfaz ayuda a administrar código de manera más eficiente.

¿Cómo utilizar una lista de interfaces en Go?

A diferencia de otros lenguajes más flexibles, Go requiere que se especifique el tipo de dato de un slice o arreglo en particular. Sin embargo, es posible simular una lista que acepte múltiples tipos de datos mediante una lista de interfaces.

Ejemplo de lista de interfaces

Podemos crear una lista que contenga distintos tipos de datos de la siguiente manera:

miInterfaz := []interface{}{"Hola", 12, 4.5}
fmt.Println(miInterfaz...)

Esto nos permite imprimir diferentes tipos de datos como cadenas, enteros o números decimales en una única estructura de datos. En la consola, obtendremos una representación uniforme de estos valores.

Consejos prácticos para el uso de interfaces en Go

  • Úsalas cuando múltiples structs compartan una funcionalidad similar.
  • Facilitan el mantenimiento y la legibilidad del código al reducir la duplicación.
  • Integra listas de interfaces para flexibilidad al combinar diferentes tipos en un mismo contenedor.

Las interfaces son, sin duda, una herramienta poderosa en Go. Nos proporcionan un control más fino sobre el código y facilitan enormemente la gestión de estructuras de datos múltiples. ¡No dudes en implementarlas en tus proyectos para descubrir su verdadero potencial y seguir expandiendo tu conocimiento en Go!

Aportes 54

Preguntas 8

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

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

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 (:

Quizá es bueno tener en cuenta que aquí no se implementan interfaces explicitamente sino implicitamente, es por eso que solo con que el método se llame área se hace la asociación!

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! 😃

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.

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.

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í.

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())
}


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
}

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)
}

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)

yo diria que esta clase explica un poco de polimorfismo con las estructuras e interfaces

Reto completo

Archivo main

package main

import (
	mpk "curso_golang_basico/src/mypackage"
	"fmt"
)

func main() {
	//Entrada de valores
	myCuadrado := mpk.Cuadrado{Base: 2}
	myRectangulo := mpk.Rectangulo{Base: 3, Altura: 5}

	//Impresión de valores
	fmt.Println(myCuadrado)
	fmt.Println(myRectangulo)

	//Calculo de valores
	mpk.Calcular(myCuadrado)
	mpk.Calcular(myRectangulo)

	//SALIDA
	// Un lado del cuadrado mide: 2 cm
	// La base del rectangulo mide: 3 cm y la altura del rectangulo mide: 5 cm
	// El área es: 4 cm2
	// El área es: 15 cm2

}

Archivo mypackage

package mypackage

import "fmt"

//PARTE 4.
type figura2D interface {
	Area() float64
}

//PARTE 1.
type Cuadrado struct {
	Base float64
}

//PARTE 1.
type Rectangulo struct {
	Base   float64
	Altura float64
}

//Parte 3.
func (c Cuadrado) Area() float64 {
	return c.Base * c.Base
}

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

//PARTE 5.
func Calcular(f figura2D) {
	fmt.Println("El área es:", f.Area(), "cm2")
}

//Para la impresión del valor entrante de uncuadrado
func (C Cuadrado) String() string {
	return fmt.Sprintf("Un lado del cuadrado mide: %v cm", C.Base)
}

//Para la impresión de los valores entrantes de un rectangulo
func (C Rectangulo) String() string {
	return fmt.Sprintf("La base del rectangulo mide: %v cm y la altura del rectangulo mide: %v cm", C.Base, C.Altura)
}

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 😃

Mi solución al reto: Estructura de archivos: ![]()![]()![](https://static.platzi.com/media/user_upload/upload-a67eb54f-6a1f-48f6-8205-ea1fcaa93359.png) go.mod: ![](https://static.platzi.com/media/user_upload/upload-09dd5b2a-0ef1-4f33-98d3-784ba3ab58d8.png) shape2D.go: ![](https://static.platzi.com/media/user_upload/upload-fc271a5e-c494-4e65-8d2f-5af54ace844a.png) square.go: ![](https://static.platzi.com/media/user_upload/upload-0c264e60-869e-4ff4-8b1e-bc1af778fd45.png) rectangle.go: ![](https://static.platzi.com/media/user_upload/upload-5c90eb0c-85a7-43b4-80a7-fe3d07f75703.png) main.go: ![](https://static.platzi.com/media/user_upload/upload-7b627051-0361-4d36-8d8d-cf8bfa8f4623.png) Resultado de correr el programa en consola: ![](https://static.platzi.com/media/user_upload/upload-8756e82f-be78-4463-b4ca-64f69bb1b4f9.png)
Si hay alguien nuevo viendo el curso, te sugiero crear listas con "any", ya que por debajo es lo mismo, dado que *any* es un alias de `interface{}`. Quedaría de la siguiente forma: ```txt conInterface := []interface{}{"hola", 12, 4.90, true} conAny := []any{"hola", 12, 4.90, true} ```
\*
figures.go: `package figures` `import ( "fmt")` `type Figuras2D interface { Area() float64}` `type Cuadrado struct { Base float64}` `type Rectangulo struct { Base float64 Altura float64}` `// Area implements Figuras2D.func (c Cuadrado) Area() float64 { return c.Base * c.Base}` `// Area implements Figuras2D.func (r Rectangulo) Area() float64 { return r.Base * r.Altura}` `func Calcular(f Figuras2D) { fmt.Println("Area: ", f.Area())}` main.go: `package main` `import ( "fmt" figures "example.com/curso_golang_platzi/src/figures")` `func main() { miCuadrado := figures.Cuadrado{Base: 3} miRectangulo := figures.Rectangulo{Base: 4, Altura: 6}` ` figures.Calcular(miCuadrado) figures.Calcular(miRectangulo)` ` //* Lista de interfaces myInterface := []interface{}{"Hola", 12, 4.90, true} fmt.Println(myInterface...)}`
```js package main import ( pk "curso_golang_platzi/src/mypackage" ) func main() { myCuadrado := pk.Cuadrado{Base: 2} myRectangulo := pk.Rectangulo{Base: 2, Altura: 4} myCirculo := pk.Circulo{Radio: 2} myTrapecio := pk.Trapecio{BaseMayor: 2, BaseMenor: 3, Altura: 5} pk.CalcularArea("Cuadrado", myCuadrado) pk.CalcularArea("Rectángulo", myRectangulo) pk.CalcularArea("Círculo", myCirculo) pk.CalcularArea("Trapecio", myTrapecio) } ``` ```js 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 } type Trapecio struct { BaseMayor float64 BaseMenor float64 Altura float64 } func (c Cuadrado) area() float64 { return c.Base * c.Base } func (r Rectangulo) area() float64 { return r.Base * r.Altura } func (c Circulo) area() float64 { const PI float64 = 3.1416 return PI * (c.Radio * c.Radio) } func (t Trapecio) area() float64 { return ((t.BaseMayor + t.BaseMenor) / 2) * t.Altura } func CalcularArea(name string, f figuras2D) { fmt.Printf("Area del %s = %.2f\n", name, f.area()) } ```
Comparto mi solución del reto: ```js package main import pk "curso_golang_platzi/src/mypackage" func main() { myCuadrado := pk.Cuadrado{Base: 2} myRectangulo := pk.Rectangulo{Base: 2, Altura: 4} pk.Calcular(myCuadrado) pk.Calcular(myRectangulo) } ``````js package mypackage import ( "fmt" "reflect" ) type figure2D 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.Base * r.Altura } func Calcular(f figure2D) { fmt.Println("Area: ", f.area()) // f.area() is a method of the interface figure2D fmt.Printf("Area de %s: %.2f\n", reflect.TypeOf(f).Name(), f.area()) // reflect.TypeOf(f).Name() returns the name of the type of the variable f } ```
package main

import (
	//pk es el alias
	pk "curso_golang_platzi/src/mypackage"
	"fmt"
)

func main() {

	myCuadrado := pk.Cuadrado{Base: 2}
	myRectangulo := pk.Rectangulo{Base: 2, Altura: 4}
	myCirculo := pk.Circulo{Radio: 5}
	myTrapecio := pk.Trapecio{Lado1: 5, Lado2: 7, Altura: 3}

	pk.Calcular(myCuadrado)
	pk.Calcular(myRectangulo)
	pk.Calcular(myCirculo)
	pk.Calcular(myTrapecio)

	//Lista de interfaces - para usar tipos diferentes en Slides

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

}
 


package mypackage

import "fmt"

const π float64 = 3.14159265

type figuras2D interface {
	area() float64
}

type Cuadrado struct {
	Base float64
}

type Rectangulo struct {
	Base   float64
	Altura float64
}

type Circulo struct {
	Radio float64
}

type Trapecio struct {
	Lado1  float64
	Lado2  float64
	Altura float64
}

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

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

func (c Circulo) area() float64 {
	return (c.Radio * c.Radio) * π
}

func (t Trapecio) area() float64 {
	return ((t.Lado1 + t.Lado2) / 2) * t.Altura
}

// Calcular - calcula áreas
func Calcular(f figuras2D) {
	fmt.Println("Area:", f.area())
}

// Se usa mayúsculas para indicar que es pública PC con accesos público
type Pc struct {
	Ram   int
	Disk  int
	Brand string
}

func (myPC Pc) Ping() {
	fmt.Println(myPC.Brand, "Pong")

}

func (myPC *Pc) DuplicateRAM() {
	myPC.Ram = myPC.Ram * 2
}

func (myPC Pc) String() string {

	return fmt.Sprintf("Tengo %d GB RAM, %d GB Disco y es una %s", myPC.Ram, myPC.Disk, myPC.Brand)
}


Reto solucionado

package main

import (
	"fmt"
	"math"
)

type calcularArea interface {
	area() float64
}

type cuadrado struct {
	Lado float64
}

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

type rectangulo struct {
	Base   float64
	Altura float64
}

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

type circulo struct {
	radio float64
}

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

type trapecio struct {
	baseMayor float64
	baseMenor float64
	altura    float64
}

func (t trapecio) area() float64 {
	return t.altura * ((t.baseMayor + t.baseMenor) / 2)
}

func hacerCalculo(f calcularArea) {
	fmt.Println(f.area())
}

func main() {
	miCuadrado := cuadrado{Lado: 7}
	miRectangulo := rectangulo{Base: 12, Altura: 5}
	miCirculo := circulo{radio: 5}
	miTrapecio := trapecio{baseMayor: 4, baseMenor: 3.5, altura: 2}

	hacerCalculo(miCuadrado)
	hacerCalculo(miRectangulo)
	hacerCalculo(miCirculo)
	hacerCalculo(miTrapecio)
}

Esto es un gran problema en Golang, lo acabo de ver. No sabemos que hace el código exactamente y no se puede auditar.

Reto

package main

import (
	figc "curso_golang_platzi/src/cuadrado"
	fig2d "curso_golang_platzi/src/figuras2d"
	figr "curso_golang_platzi/src/rectangulo"
	"fmt"
)

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

func main() {
	mySquare := figc.Cuadrado{}
	mySquare.ColocarBase(2)
	myRectangle := figr.Rectangulo{}
	myRectangle.ColocarBase(2)
	myRectangle.ColocarAltura(3)

	calculate(mySquare)
	calculate(myRectangle)
}
package cuadrado

type Cuadrado struct {
	base float64
}

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

func (c *Cuadrado) ColocarBase(base float64) {
	c.base = base
}
package rectangulo

type Rectangulo struct {
	base   float64
	altura float64
}

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

func (c *Rectangulo) ColocarBase(base float64) {
	c.base = base
}

func (c *Rectangulo) ColocarAltura(altura float64) {
	c.altura = altura
}
package figuras2d

type Figuras2D interface {
	Area() float64
}

Una Interface tan sólo es un método que lo comparten varios Structs

El reto si ven algo que se pueda mejorar por favor me lo indican para entender mejor el tema. Muchas gracias !

package main

import (
	"fmt"
	"math"
)

type figuras2D interface{
	area() float64
}

type cuadrado struct{
	base float64
}
type rectangulo struct{
	base float64
	altura float64
}
type circulo struct{
	radio float64	
}
type trapecio struct{
	base1 float64
	base2 float64
	altura 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 (math.Pi * (ci.radio * ci.radio))
}
func(t trapecio) area() float64{
	return (((t.base1 + t.base2) / 2) * t.altura)
}
func calculador (f figuras2D){
	fmt.Println("Area: ", f.area())
}


func main() {
	myCuadrado := cuadrado{base: 2}
	myRectangulo := rectangulo{base: 2, altura: 3}
	myCirculo := circulo{radio: 10}
	myTrapecio := trapecio{base1: 4, base2: 3, altura: 8}

	calculador(myCuadrado)
	calculador(myRectangulo)
	calculador(myCirculo)
	calculador(myTrapecio)
}

Resume Code

package main

import shapes "curso_golang_platzi/src/mypackage"

func main() {
	s1 := shapes.NewTriangle(5, 5)
	s2 := shapes.NewSquare(5)
	s3 := shapes.NewRectangle(2, 5)
	shapes.Calculate(s1)
	shapes.Calculate(s2)
	shapes.Calculate(s3)
}
package mypackage

import "fmt"

//The interface is used for repetitive methods
type shape interface {
	Area() float64
}

type square struct {
	side float64
}

type rectangle struct {
	side float64
	base float64
}

type triangle struct {
	base   float64
	height float64
}

func NewTriangle(base float64, height float64) *triangle {
	t := new(triangle)
	t.base = base
	t.height = height
	return t
}

func (t triangle) Area() float64 {
	return (t.base * t.height) / 2
}

func (t triangle) GetBase() float64 {
	return t.base
}

func (t *triangle) SetBase(base float64) {
	t.base = base
}

func (t triangle) GetHeight() float64 {
	return t.height
}

func (t *triangle) SetHeight(height float64) {
	t.height = height
}

func (t triangle) String() string {
	return fmt.Sprintf("Base: %f\nHeight: %f\n\n", t.base, t.height)
}

func NewRectangle(base float64, side float64) *rectangle {
	r := new(rectangle)
	r.base = base
	r.side = side
	return r
}

func (r rectangle) Area() float64 {
	return r.base * r.side
}

func (r rectangle) GetBase() float64 {
	return r.base
}

func (r *rectangle) SetBase(base float64) {
	r.base = base
}

func (r rectangle) GetSide() float64 {
	return r.side
}

func (r *rectangle) SetSide(side float64) {
	r.side = side
}

func (r rectangle) String() string {
	return fmt.Sprintf("Side: %f\nBase: %f\n\n", r.side, r.base)
}

func NewSquare(side float64) *square {
	s := new(square)
	s.side = side
	return s
}

func (s square) Area() float64 {
	return s.side * s.side
}

func (s square) GetSide() float64 {
	return s.side
}

func (s *square) SetSide(side float64) {
	s.side = side
}

func (s square) String() string {
	return fmt.Sprintf("Base: %f\n\n", s.side)
}

//Function of the interface
func Calculate(s shape) {
	fmt.Print(s)
	fmt.Printf("Area: %f\n\n", s.Area())
}

func mypackage() {

}

Buenas muchach@s 👋
Paso mis apuntes con otro ejemplo:

package main

import (
	"fmt"
	"math"
)

type BH struct {
	Base   float32
	Altura float32
}

type Rectangulo struct {
	BH
}

type Triangulo struct {
	L1 float32
	L2 float32
	L3 float32
	BH
}
type Cuadrado struct {
	Lado float32
}

type Shape interface {
	Area() float32
	Perimeter() float32
	String() string
}

func (r *Rectangulo) Area() float32 {
	return r.Altura * r.Base
}
func (r *Rectangulo) Perimeter() float32 {
	return 2*r.Altura + 2*r.Base
}

func (r *Rectangulo) String() string {
	return fmt.Sprintf("Area: %v  | Perimetro: %v", r.Area(), r.Perimeter())

}

func (c *Cuadrado) Perimeter() float32 {
	return 4 * c.Lado
}

func (c *Cuadrado) Area() float32 {
	return float32(math.Pow(float64(c.Lado), 2))

}

func (c *Cuadrado) String() string {
	return fmt.Sprintf("Area: %v  | Perimetro: %v", c.Area(), c.Perimeter())

}
func (t *Triangulo) Perimeter() float32 {
	return t.L1 + t.L2 + t.L3
}

func (t *Triangulo) Area() float32 {
	return t.Base * t.Altura
}
func (t *Triangulo) String() string {
	return fmt.Sprintf("Area: %v  | Perimetro: %v", t.Area(), t.Perimeter())

}

func Inprimir(s Shape) {
	fmt.Println(s.String())
}

func main() {

	var cuadrado = Cuadrado{Lado: 5}

	var triangulo = Triangulo{L1: 5, L2: 3, L3: 6, BH: (BH{Base: 10, Altura: 10})}
	Inprimir(&cuadrado)
	Inprimir(&triangulo)

}

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

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)
	}

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)

}

Otra forma de imprimir el area de cada Struct:

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

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())
}



> 

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)
	}
En estos momentos extraño Java, ahí todo es bonito
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