parameter interfaces inicializar golang create go struct interface

inicializar - ¿Por qué se necesitan interfaces en Golang?



inicializar struct golang (3)

Aquí mostraré dos casos de uso interesantes de interfaces en Go:

1- Ver estas dos interfaces simples:

type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) }

Usando estas dos interfaces simples puedes hacer esta magia interesante:

package main import ( "bufio" "bytes" "fmt" "io" "os" "strings" ) func main() { file, err := os.Create("log.txt") if err != nil { panic(err) } defer file.Close() w := io.MultiWriter(file, os.Stdout) r := strings.NewReader("You''ll see this string twice!!/n") io.Copy(w, r) slice := []byte{33, 34, 35, 36, 37, 38, 39, 10, 13} io.Copy(w, bytes.NewReader(slice)) // !"#$%&'' buf := &bytes.Buffer{} io.Copy(buf, bytes.NewReader(slice)) fmt.Println(buf.Bytes()) // [33 34 35 36 37 38 39 10 13] _, err = file.Seek(0, 0) if err != nil { panic(err) } r = strings.NewReader("Hello/nWorld/nThis/nis/nVery/nnice/nInterfacing./n") rdr := io.MultiReader(r, file) scanner := bufio.NewScanner(rdr) for scanner.Scan() { fmt.Println(scanner.Text()) } }

Salida:

You''ll see this string twice!! !"#$%&'' [33 34 35 36 37 38 39 10 13] Hello World This is Very nice Interfacing. You''ll see this string twice!! !"#$%&''

Espero que este código sea lo suficientemente claro:
lee desde la cadena usando strings.NewReader y escribe simultáneamente tanto en file como en os.Stdout usando io.MultiWriter con solo io.Copy(w, r) . Luego lee el segmento usando bytes.NewReader(slice) y escribe simultáneamente tanto en el file como en el file os.Stdout . Luego copie el segmento en el búfer io.Copy(buf, bytes.NewReader(slice)) luego vaya al origen del archivo usando file.Seek(0, 0) luego lea primero de la cadena usando strings.NewReader luego continúe leyendo ese file usando io.MultiReader(r, file) y bufio.NewScanner e Imprime todo a continuación utilizando fmt.Println(scanner.Text()) .

2- Y este es otro uso interesante de la interfaz:

package main import "fmt" func main() { i := show() fmt.Println(i) // 0 i = show(1, 2, "AB", ''c'', ''d'', []int{1, 2, 3}, [...]int{1, 2}) fmt.Println(i) // 7 } func show(a ...interface{}) (count int) { for _, b := range a { if v, ok := b.(int); ok { fmt.Println("int: ", v) } } return len(a) }

salida:

0 int: 1 int: 2 7

Y un buen ejemplo para ver: Explicar las aserciones de tipos en Go

También vea: Ir: ¿Cuál es el significado de interfaz {}?

En Golang, usamos estructuras con métodos de receptor. Todo está perfecto hasta aquí.
Sin embargo, no estoy seguro de qué son las interfaces. Definimos métodos en estructuras y, si queremos implementar un método en una estructura, lo escribimos de todos modos de nuevo bajo otra estructura.
Esto significa que las interfaces parecen ser solo definiciones de métodos, que solo ocupan espacio adicional innecesario en nuestra página.

¿Hay algún ejemplo que explique por qué necesito una interfaz?


La interfaz proporciona algunos tipos de genéricos. Piensa en escribir pato.

type Reader interface{ Read() } func callRead(r Reader){ r.Read() } type A struct{ } func(_ A)Read(){ } type B struct{ } func(_ B)Read(){ }

Está bien pasar las estructuras A y B a callRead , porque ambos implementan la interfaz del Reader. Pero si sin interfaz, deberíamos escribir dos funciones para A y B

func callRead(a A){ a.Read() } func callRead2(b B){ b.Read() }


Las interfaces son un tema demasiado grande para dar una respuesta completa aquí, pero algunas cosas para aclarar su uso.

Las interfaces son una herramienta . Si los usa o no, depende de usted, pero pueden aclarar el código y pueden proporcionar una API agradable entre paquetes, o clientes (usuarios) y servidores (proveedores).

Sí, puede crear su propio tipo de struct y puede "adjuntarle" métodos, por ejemplo:

type Cat struct{} func (c Cat) Say() string { return "meow" } type Dog struct{} func (d Dog) Say() string { return "woof" } func main() { c := Cat{} fmt.Println("Cat says:", c.Say()) d := Dog{} fmt.Println("Dog says:", d.Say()) }

Ya podemos ver algunas repeticiones en el código anterior: cuando se hace que tanto Cat como Dog digan algo. ¿Podemos manejar tanto como el mismo tipo de entidad, como animal ? Realmente no. Claro que podríamos manejar ambos como interface{} , pero si lo hacemos, no podemos llamar a su método Say() porque un valor de tipo interface{} no define ningún método.

Existe una cierta similitud en los dos tipos anteriores: ambos tienen un método Say() con la misma firma (parámetros y tipos de resultados). Podemos capturar esto con una interfaz:

type Sayer interface { Say() string }

La interfaz solo contiene las firmas de los métodos, pero no su implementación .

Tenga en cuenta que en Go, un tipo implementa implícitamente una interfaz si su conjunto de métodos es un superconjunto de la interfaz. No hay declaración de la intención. ¿Qué significa esto? Nuestros tipos anteriores de Dog y Cat ya implementan esta interfaz de Sayer , aunque esta definición de interfaz ni siquiera existía cuando los escribimos anteriormente, y no los tocamos para marcarlos o algo. Simplemente lo hacen.

Las interfaces especifican el comportamiento . Un tipo que implementa una interfaz significa que ese tipo tiene todos los métodos que la interfaz "prescribe".

Dado que ambos implementan Sayer , podemos manejar ambos como un valor de Sayer , tienen esto en común. Vea cómo podemos manejar ambos en unidad:

animals := []Sayer{c, d} for _, a := range animals { fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say()) }

(Esa parte de reflejo es solo para obtener el nombre del tipo, no le dé mucha importancia a partir de ahora).

La parte importante es que podríamos manejar tanto a Cat como a Dog del mismo tipo (un tipo de interfaz), y trabajar con ellos / usarlos. Si estuvieras rápidamente en la creación de tipos adicionales con un método Say() , podrían alinearse al lado de Cat and Dog :

type Horse struct{} func (h Horse) Say() string { return "neigh" } animals = append(animals, Horse{}) for _, a := range animals { fmt.Println(reflect.TypeOf(a).Name(), "says:", a.Say()) }

Digamos que desea escribir otro código que funcione con estos tipos. Una función auxiliar:

func MakeCatTalk(c Cat) { fmt.Println("Cat says:", c.Say()) }

Sí, la función anterior funciona con Cat y con nada más. Si quisieras algo similar, tendrías que escribirlo para cada tipo. No hace falta decir lo malo que es esto.

Sí, podría escribirlo para tomar un argumento de interface{} , y usar aserción de tipo o interruptores de tipo , lo que reduciría el número de funciones de ayuda, pero aún así se ve muy feo.

¿La solución? Sí, interfaces. Simplemente declare que la función toma un valor de un tipo de interfaz que define el comportamiento que desea hacer con eso, y eso es todo:

func MakeTalk(s Sayer) { fmt.Println(reflect.TypeOf(s).Name(), "says:", s.Say()) }

Puede llamar a esta función con un valor de Cat , Dog , Horse o cualquier otro tipo que no sepa, hasta ahora, que tiene un método Say() . Guay.

Prueba estos ejemplos en el Go Playground .