Explicación de la interfaz Go Empty

Interfaces, interfaz {}, conversiones

Una interfaz en Go especifica unconjunto de métodos. Se dice que cualquier tipo que implemente este conjunto de métodosimplementar la interfaz.

Una interfaz se implementa de forma implícita. No hayimplementospalabra clave, utilizada en otros idiomas. Si un tipo define todo el conjunto de métodos de una interfaz, lo implementa. Se llama tipado estructural, el equivalente en tiempo de compilación deescribiendo pato.

Si camina como un pato, nada como un pato y grazna como un pato, es un pato.

Importante: en Go, la interfaz abstrae un conjunto de métodos (acciones), no datos.

Ejemplo

El siguiente ejemplo tomado deCómo usar interfaces en Goilustra una interfaz básica de un animal que puede hablar y diferentes estructuras que satisfacen la interfaz:

type Animal interface {
    Speak() string
}

type Dog struct { }

func (d Dog) Speak() string { return “Woof!” }

type Cat struct { }

func (c Cat) Speak() string { return “Meow!” }

type Llama struct { }

func (l Llama) Speak() string { return “???” }

type JavaProgrammer struct { }

func (j JavaProgrammer) Speak() string { return “Design patterns!” }

Puedes construir un [] Animal y correrSpeak()sobre su contenido:

func main() {
    animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
    for _, animal := range animals {
        fmt.Println(animal.Speak())
    }
}

tocar

La interfaz vacía

losAnimalLa interfaz es pequeña y agradable, pero hay algo aún más simple, aunque un concepto algo complejo de entender para los principiantes: la interfaz vacía.

interface{}es la interfaz Go Empty, un concepto clave. Cada tipo lo implementa por definición.

Una interfaz es un tipo, por lo que puede definir, por ejemplo:

type Dog struct {
    Age interface{}
}

y también puede pasar un tipo de interfaz vacío como parámetro de función:

func Eat(t interface{}) {
    // ...
}

Aceptarinterface{}no significa que la función acepta cualquier tipo, sino que significa que Eat acepta un valor deinterface{}escribe.

En tiempo de ejecución, Go convertirá el valor real pasado a uninterface{}valor.

Si define un campo en una estructura con tipointerface{}, puede asignarle un valor de cualquier tipo. Por ejemplo:

package main

import “fmt”

type Dog struct { Age interface{} }

func main() { dog := Dog{} dog.Age = “3” fmt.Printf("%#v %T\n", dog.Age, dog.Age)

<span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span> = <span style="color:#ae81ff">3</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"%#v %T\n"</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>)

<span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span> = <span style="color:#e6db74">"not really an age"</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"%#v %T"</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>)

}

tocar

huellas dactilares

"3" string
3 int
"not really an age" string

Por supuesto, esto no se limita a los tipos básicos: puede almacenar un segmento, un mapa, cualquier estructura personalizada allí.

Cómo se representa la interfaz internamente

Internamente, una interfazvalorson doswords, conjuntos de bytes.

Una palabra apunta al tipo de valor subyacente. Una palabra apunta a los datos.

Conversiones

Cuando lo hicimosanimals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}anteriormente, Go convertía automáticamente todos nuestros tipos de animales específicos en un tipo de Animal. Cada elemento de esa porción ahora es de tipo Animal, con el tipo subyacente apuntando a la especie específica, como Perro, Gato y Llama.

Pero si un método acepta[]interface{}por ejemplo, no podemos simplemente pasaranimalsa él, porque el tipo no coincide. Necesitamos queconvertir explícitamente cadaAnimala unainterface{}antes, con un bucle, como se describe en el¿Puedo convertir una [] T en una [] interfaz {}PREGUNTAS MÁS FRECUENTES:

t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
    s[i] = v
}

Determine el tipo subyacente de uninterface{}

Si un valor es de tipointerface{}, es posible que desee determinar el tipo subyacente. ¿Cómo? Con un interruptor encendido.(type), me gustaGo eficazexplica:

También se puede utilizar un conmutador para descubrir el tipo dinámico de una variable de interfaz. Este tipo de cambio utiliza la sintaxis de una aserción de tipo con la palabra clave type entre paréntesis. Si el conmutador declara una variable en la expresión, la variable tendrá el tipo correspondiente en cada cláusula. También es idiomático reutilizar el nombre en tales casos, declarando de hecho una nueva variable con el mismo nombre pero de un tipo diferente en cada caso.

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

Más tutoriales de go: