¿Cuál es el significado de interfaz{}?

Resuelto user asked hace 10 años • 8 respuestas

Soy nuevo en las interfaces y estoy intentando realizar una solicitud SOAP mediante github.

No entiendo el significado de

Msg interface{}

en este código:

type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

He observado la misma sintaxis en

fmt.Println

pero no entiendo lo que se está logrando con

interface{}
user avatar Apr 18 '14 13:04 user
Aceptado

Nota: Go 1.18 (primer trimestre de 2022) cambia el nombre interface{}a any(alias de interface{}).
Consulte el problema 49884 , CL 368254 y confirme 2580d0e .
Vea la última parte de esta respuesta.


Puede consultar el artículo " Cómo utilizar interfaces en Go " (basado en la " Descripción de interfaces de Russ Cox "):

¿ Qué es una interfaz?

Una interfaz es dos cosas:

  • es un conjunto de métodos,
  • pero también es un tipo

El interface{}tipo (o anycon Go 1.18+), la interfaz vacía es la interfaz que no tiene métodos.

Dado que no existe una palabra clave implements, todos los tipos implementan al menos cero métodos y la satisfacción de una interfaz se realiza automáticamente, por lo tanto, todos los tipos satisfacen la interfaz vacía .
Eso significa que si escribe una función que toma un interface{}valor como parámetro, puede proporcionarle cualquier valor a esa función .

(Eso es lo que Msgrepresenta en tu pregunta: cualquier valor)

func DoSomething(v interface{}) {
   // ...
}


func DoSomething(v any) {
   // ...
}

Aquí es donde se vuelve confuso:

dentro de la DoSomethingfunción, ¿ cuál es vel tipo?

A los tuzas principiantes se les hace creer que “ ves de cualquier tipo”, pero eso está mal.
vno es de ningún tipo; es de interface{}tipo .

Al pasar un valor a la DoSomethingfunción, el tiempo de ejecución de Go realizará una conversión de tipo (si es necesario) y convertirá el valor en un interface{}valor .
Todos los valores tienen exactamente un tipo en tiempo de ejecución, y vel tipo estático es interface{}(o anycon Go 1.18+).

Un valor de interfaz se construye con dos palabras de datos :

  • se usa una palabra para señalar una tabla de métodos para el tipo subyacente del valor,
  • y la otra palabra se usa para señalar los datos reales que contiene ese valor.

Anexo: aquí es donde el artículo de Russ es bastante completo con respecto a la estructura de la interfaz:

type Stringer interface {
    String() string
}

Los valores de la interfaz se representan como un par de dos palabras que dan un puntero a información sobre el tipo almacenado en la interfaz y un puntero a los datos asociados.
Asignar b a un valor de interfaz de tipo Stringer establece ambas palabras del valor de interfaz.

http://research.swtch.com/gointer2.png

La primera palabra en el valor de la interfaz apunta a lo que yo llamo una tabla de interfaz o itable (se pronuncia i-table; en las fuentes de tiempo de ejecución, el nombre de la implementación en C es Itab).
La itable comienza con algunos metadatos sobre los tipos involucrados y luego se convierte en una lista de punteros de función.
Tenga en cuenta que el itable corresponde al tipo de interfaz, no al tipo dinámico .
En términos de nuestro ejemplo, el itable para Stringercontener el tipo Binary enumera los métodos utilizados para satisfacer Stringer, que es simplemente String: Los otros métodos de Binary ( Get) no aparecen en el archivo itable.

La segunda palabra en el valor de la interfaz apunta a los datos reales , en este caso una copia de b.
La asignación var s Stringer = bhace una copia ben lugar de señalar bpor la misma razón que var c uint64 = bhace una copia: si bluego cambia, sya cse supone que debe tener el valor original, no el nuevo.
Los valores almacenados en las interfaces pueden ser arbitrariamente grandes, pero solo se dedica una palabra a contener el valor en la estructura de la interfaz, por lo que la asignación asigna una porción de memoria en el montón y registra el puntero en la ranura de una palabra.


El problema 33232 parece señalarse anycomo un alias interface{}en Go 1.18 (primer trimestre de 2022)

Russ Cox explica :

  1. ' any' estar solo para restricciones es un detalle que estará en cada artículo sobre genéricos: libros, publicaciones de blogs, etc. Si creemos que es probable que eventualmente lo permitamos, tiene sentido permitirlo desde el principio y evitar invalidar todo ese material escrito.

  2. ' any' Ser sólo para restricciones es un recorte inesperado que reduce la generalidad y la ortogonalidad de los conceptos. Es fácil decir "esperemos y veremos", pero la prescripción de usos tiende a crear características mucho más irregulares que la generalidad total. También vimos esto con alias de tipo (y afortunadamente resistimos casi todos los recortes propuestos).

  3. Si " any" está permitido en códigos genéricos pero no en códigos no genéricos, entonces podría alentar a las personas a abusar de los genéricos simplemente porque " any" es mejor de escribir que " interface{}", cuando la decisión sobre genéricos o no realmente debería tomarse considerando otros factores.

  4. Si permitimos ' any' también para el uso ordinario no genérico, entonces ver interface{}en el código podría servir como una especie de señal de que el código es anterior a los genéricos y aún no ha sido reconsiderado en el mundo posgenérico. Parte del código utilizado interface{}debería utilizar genéricos. Otro código debería seguir utilizando interfaces.
    Reescribirlo de una forma u otra para eliminar el texto " interface{}" daría a las personas una forma clara de ver lo que habían actualizado y lo que no. (Por supuesto, algún código que podría ser mejor con genéricos aún debe usarse interface{}por razones de compatibilidad con versiones anteriores, pero aún se puede actualizar para confirmar que la decisión fue considerada y tomada).

Ese hilo también incluye una explicación sobreinterface{} :

No es un diseño especial, sino una consecuencia lógica de la sintaxis de declaración de tipos de Go.

Puede utilizar interfaces anónimas con más de cero métodos:

func f(a interface{Foo(); Bar()}) {
   a.Foo()
   a.Bar()
}

De manera análoga a cómo se pueden usar estructuras anónimas en cualquier lugar donde se espere un tipo:

func f(a struct{Foo int; Bar string}) {
   fmt.Println(a.Foo)
   fmt.Println(a.Bar)
}

Una interfaz vacía coincide con todos los tipos porque todos los tipos tienen al menos cero métodos.

Eliminar interface{}significaría eliminar toda la funcionalidad de la interfaz del idioma si desea mantener la coherencia o no desea introducir un caso especial.

VonC avatar Apr 18 '2014 06:04 VonC

interface{}significa que puede poner valores de cualquier tipo, incluido su propio tipo personalizado. Todos los tipos en Go satisfacen una interfaz vacía ( interface{}es una interfaz vacía).
En su ejemplo, el campo Mensaje puede tener valores de cualquier tipo.

Ejemplo:

package main

import (
    "fmt"
)

type Body struct {
    Msg interface{}
}

func main() {
    b := Body{}
    b.Msg = "5"
    fmt.Printf("%#v %T \n", b.Msg, b.Msg) // Output: "5" string
    b.Msg = 5

    fmt.Printf("%#v %T", b.Msg, b.Msg) //Output:  5 int
}

ir al patio de recreo

Minty avatar Dec 09 '2014 15:12 Minty

Ya hay buenas respuestas aquí. Permítanme agregar el mío también para otros que quieran entenderlo intuitivamente:


Interfaz

Aquí hay una interfaz con un método:

type Runner interface {
    Run()
}

Entonces, cualquier tipo que tenga un Run()método satisface la interfaz Runner:

type Program struct {
    /* fields */
}

func (p Program) Run() {
    /* running */
}

func (p Program) Stop() {
    /* stopping */
}
  • Aunque el tipo Programa también tiene un método Stop, aún satisface la interfaz Runner porque todo lo que se necesita es tener todos los métodos de una interfaz para satisfacerla.

  • Entonces, tiene un método Run y ​​satisface la interfaz Runner.


Interfaz vacía

Aquí hay una interfaz vacía con nombre sin ningún método:

type Empty interface {
    /* it has no methods */
}

Entonces cualquier tipo satisface esta interfaz. Porque no se necesita ningún método para satisfacer esta interfaz. Por ejemplo:

// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty

a = 5
a = 6.5
a = "hello"

Pero, ¿el tipo de programa anterior lo satisface? Sí:

a = Program{} // ok

interface{} es igual a la interfaz vacía anterior.

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"

Como ves, no tiene nada de misterioso, pero es muy fácil abusar de él. Manténgase alejado de él tanto como pueda.


https://play.golang.org/p/A-vwTddWJ7G

Inanc Gumus avatar Jun 05 '2018 20:06 Inanc Gumus