ir a las preguntas de la entrevista (regular)

1. ¿Qué es una gorutina? ¿En qué se diferencia del hilo?
Respuesta: Goroutine es un subproceso ligero en el lenguaje Go, que está programado por el sistema de tiempo de ejecución del lenguaje Go. A diferencia de los subprocesos, un programa puede crear miles de gorrutinas, porque las gorrutinas se ejecutan en un subproceso, por lo que el costo de crear gorrutinas es muy pequeño. Además, la comunicación entre rutinas se realiza a través de canales en lugar de memoria compartida, por lo que se puede evitar el problema de sincronización de la memoria compartida.

2. ¿Qué es un canal? ¿Qué hace? ¿Cómo crear un canal?
Respuesta: Un canal es un mecanismo de comunicación entre múltiples gorutinas, que proporciona funciones de sincronización y comunicación. A través de los canales, una gorutina puede enviar datos a otra gorutina y otra gorutina puede recibir datos del canal. La forma de crear un canal es usar la función make, como: ch := make(chan int).

3. ¿Qué es una rebanada? ¿En qué se diferencia de una matriz? ¿Cómo crear y manipular rebanadas?
Respuesta: un segmento es una matriz dinámica que se puede expandir automáticamente en tiempo de ejecución. La principal diferencia entre los segmentos y las matrices es que los segmentos tienen una longitud variable, mientras que las matrices tienen una longitud fija. La forma de crear una división es usar la función make o crear una expresión de división. Los sectores se pueden operar utilizando expresiones de índice y sector, por ejemplo: s[1:3] significa extraer los elementos con el subíndice 1 al subíndice 2 del sector s.

4. ¿Qué es un mapa? ¿Cómo crear y manipular mapas? ¿Cómo eliminar el par clave-valor en el mapa?
Respuesta: un mapa es una tabla hash que se utiliza para almacenar pares clave-valor. Las claves en un mapa son únicas, mientras que los valores pueden repetirse. La forma de crear un mapa es usar la función make, como: m := make(map[string]int). Puede usar la función de índice y eliminación para operar el mapa, como: m["uno"] = 1, eliminar(m, "uno").

5. ¿Qué es una interfaz? ¿Qué hace? ¿Cómo definir e implementar la interfaz?
Respuesta: Una interfaz es un tipo abstracto que define un conjunto de métodos. Cualquier tipo que implemente todos los métodos en una interfaz es un tipo de implementación de ese tipo de interfaz. La interfaz se define utilizando la palabra clave type y la palabra clave interface, como: type MyInterface interface { method1() int method2() string }. La forma de implementar una interfaz es implementar todos los métodos definidos en la interfaz.

6. ¿Qué es la instrucción diferir en Go? ¿Qué hace? ¿Cómo usar la declaración diferida?
Respuesta: La sentencia defer es una sentencia que se usa para realizar algunas operaciones cuando la función sale, como cerrar archivos, liberar recursos, etc. La declaración de aplazamiento se puede usar en cualquier parte de la función, y puede haber varias declaraciones de aplazamiento, y su orden de ejecución es el último en entrar, el primero en salir.

7. ¿Cuál es el mecanismo de recolección de basura en Go? cómo funciona ¿Cómo evitar el impacto de la recolección de basura?
Respuesta: El mecanismo de recolección de elementos no utilizados en Go utiliza el algoritmo de marcar y barrer, que analiza periódicamente las variables del programa que ya no se utilizan y las marca como elementos no utilizados. Cuando el espacio ocupado por la basura supera un cierto umbral, el recolector de basura comenzará a trabajar para limpiar el espacio ocupado por las variables marcadas como basura. El recolector de basura de Go es concurrente, por lo que puede ejecutarse automáticamente durante la ejecución del programa sin bloquear la ejecución del programa.

Para evitar el impacto de la recolección de basura, la generación de basura puede reducirse mediante:

Utilice la pila en lugar del montón siempre que sea posible Puede evitar la asignación de memoria en el montón utilizando la distinción entre tipos de valor y tipos de puntero.
Utilice grupos de objetos para reutilizar objetos y evitar la sobrecarga de crear y destruir objetos repetidamente.
Utilice el grupo de memoria proporcionado por la biblioteca estándar, como sync.Pool.
8. ¿Qué es el contexto en Go? ¿Qué hace? ¿Cómo crear y usar contexto?
Respuesta: El contexto (contexto) en Go es un objeto que contiene valores relacionados con la solicitud, señales de cancelación y plazos, que pueden pasar información entre varias rutinas. La función principal del contexto es pasar la información relevante de la solicitud al procesar la solicitud, como la fecha límite de la solicitud, la identidad del usuario, la identificación de seguimiento de la solicitud, etc. El contexto se puede pasar de forma segura entre múltiples gorutinas y se puede crear mediante funciones como context.WithCancel, context.WithTimeout, context.WithDeadline, etc.

Los pasos principales para usar el contexto son los siguientes:

Cree un contexto raíz en la entrada de la solicitud, como: ctx := context.Background().
Pase el contexto raíz como parámetro a cada controlador de solicitudes.
En la función de procesamiento de solicitudes, use ctx.Value para obtener información relacionada con la solicitud, como: ID de usuario := ctx.Value("id_usuario").
Si la solicitud debe devolver el resultado antes de la fecha límite, puede usar ctx.WithDeadline o ctx.WithTimeout para crear un contexto secundario con una fecha límite.
Si es necesario cancelar la solicitud, puede usar ctx.WithCancel para crear un contexto secundario con una señal de cancelación y llamar a la función de cancelación cuando sea necesario cancelar la solicitud.
9. ¿Cómo manejar los errores en Go? ¿Cómo personalizar los errores? ¿Cómo capturar y manejar excepciones?
Respuesta: El mecanismo de manejo de errores en Go expresa el resultado de la ejecución de la función devolviendo un valor de tipo de error. Cuando la función se ejecuta correctamente, el valor de error es nulo; cuando la función falla, el valor de error es distinto de cero y contiene un mensaje de error. Al manejar errores, puede usar una declaración if o una declaración switch para determinar el valor del error. como:

result, err := SomeFunction()
if err != nil { // manejar el error } else { // manejar el resultado } Puede crear errores personalizados personalizando la interfaz de error, como:




escriba MyError struct { Cadena de mensaje }

func (e *MyError) Error() string { return e.Message } En términos de captura y manejo de excepciones, Go no proporciona un mecanismo de prueba y captura como Java o Python. Por lo tanto, el método de manejo de errores de Go es más simple y más directo. Generalmente, el error devuelto se juzga en el lugar donde se llama a la función y se realiza el procesamiento correspondiente.


10. ¿Qué es la reflexión? ¿Qué hace? ¿Cómo manipular variables y tipos usando la reflexión?
Respuesta: La reflexión se refiere a la obtención dinámica de la información de tipo del objeto cuando el programa se está ejecutando y puede modificar el valor, el tipo y el atributo del objeto en tiempo de ejecución. En el lenguaje Go, la reflexión se implementa a través del paquete reflect.

Las principales funciones de la reflexión son las siguientes:

Obtener dinámicamente la información de tipo de un objeto.
Obtener y establecer dinámicamente los valores de propiedad de los objetos.
Invoque dinámicamente métodos en un objeto en tiempo de ejecución.
Reflection puede manipular variables y tipos a través de Type y Value en el paquete reflect.

reflect.Type indica la información de tipo de la variable, que se puede obtener a través del método Type de Value. Tipo contiene el nombre del tipo, el nombre del paquete, el método y otra información. La información básica del tipo se puede obtener a través del método Type, como el método Kind puede obtener el tipo básico del tipo, y el método NumField puede obtener el número de campos de la estructura, etc.

reflect.Value representa el valor de la variable, que se puede obtener a través de reflect.ValueOf. Valor contiene el valor de la variable, información de tipo y métodos para manipular la variable. El valor de la variable se puede obtener o establecer a través del método Value, como el método Int puede obtener el valor de la variable de tipo int, y el método SetInt puede establecer el valor de la variable de tipo int.

Reflection puede manipular variables y tipos a través de los siguientes pasos:

Obtenga la información de tipo de la variable: use reflect.ValueOf para obtener el valor de la variable, y luego use el método Type de Value para obtener la información de tipo.

Obtenga o establezca el valor de la variable: use el método Value para obtener o establecer el valor de la variable, por ejemplo, el método Int puede obtener el valor de la variable de tipo int y el método SetInt puede establecer el valor de la variable int. variable tipo.

Obtener las propiedades de las variables: use el método de campo de Value para obtener el valor de campo de la estructura y use el método de índice de Value para obtener el valor de elemento de la matriz o división.

El método de llamar a la variable: use el método Call de Value para llamar al método de la variable. Al llamar al método, debe usar ValueOf para convertir el parámetro al tipo de valor.

Cabe señalar que debido a que la reflexión obtendrá dinámicamente información de tipo en tiempo de ejecución, traerá una cierta pérdida de rendimiento. En el desarrollo real, debe intentar evitar usar demasiado la reflexión para mejorar el rendimiento del programa.

11. Explique que las funciones en Golang son valores de primera clase.
Respuesta: Las funciones en Golang son valores de primera clase, que se pueden pasar como parámetros, valores devueltos, valores asignados y usados ​​como campos de estructura. Esto significa que las funciones en Golang se pueden manipular y procesar como otros valores, lo que permite funciones avanzadas como cierres de funciones, funciones de orden superior y programación funcional.

12. Explique qué se entiende por concurrencia segura en Golang.
Respuesta: La seguridad de la concurrencia significa que en la programación concurrente, el programa puede manejar correctamente múltiples accesos concurrentes a los recursos compartidos. Golang proporciona mecanismos como operaciones atómicas, exclusión mutua, bloqueos de lectura y escritura y variables de condición para garantizar la seguridad de la concurrencia.

13. ¿Qué herramientas y métodos existen para la gestión de paquetes y la gestión de dependencias en Golang?
Respuesta: La gestión de paquetes y la gestión de dependencias en Golang se pueden implementar mediante go mod, dep, glide y otras herramientas. go mod es una herramienta de administración de paquetes proporcionada oficialmente por Golang, que puede descargar y administrar automáticamente paquetes dependientes y admite funciones como la administración de versiones y el almacén privado. dep y glide son herramientas de administración de paquetes de terceros que también se pueden usar para la administración de dependencias de los proyectos de Golang.

14. ¿Cómo usar Golang para realizar pruebas? ¿Qué marcos y herramientas de prueba hay en Golang?
Respuesta: Golang puede usar el paquete de prueba y el comando go test para probar. El paquete de prueba proporciona un marco de prueba y funciones de aserción, y puede escribir diferentes tipos de pruebas, como pruebas unitarias y pruebas de integración. Al mismo tiempo, también puede utilizar marcos y herramientas de prueba de terceros, como Ginkgo, Testify, GoConvey, etc., para mejorar la funcionalidad y la legibilidad de la prueba.

15. ¿Presenta las características y ventajas de Golang?
Respuesta: gran capacidad de programación simultánea, excelente gestión de la memoria, sintaxis concisa, alto rendimiento, buena legibilidad del código, seguridad de tipo estático, soporte multiplataforma, etc. Al mismo tiempo, también tiene las siguientes características y ventajas:

Alta eficiencia en el uso de la memoria: el mecanismo de recolección de basura de Golang puede recuperar automáticamente la memoria no utilizada en tiempo de ejecución, y el mecanismo de puntero de Golang también puede reducir las copias de memoria innecesarias, lo que hace que el uso de la memoria de Golang sea más eficiente.

Buena portabilidad de plataforma: Golang puede ejecutarse en diferentes sistemas operativos y plataformas de hardware, y los programas se pueden implementar fácilmente en diferentes entornos a través de la compilación cruzada.

Biblioteca estándar enriquecida: la biblioteca estándar de Golang proporciona una gran cantidad de funciones, que incluyen programación de red, cifrado y descifrado, procesamiento de texto, compresión y descompresión, expresiones regulares, etc., que pueden satisfacer las necesidades de la mayoría de las aplicaciones.

Estilo de código coherente: Golang impone un estilo de código y una convención de nomenclatura coherentes, lo que facilita la colaboración y la comunicación entre diferentes desarrolladores.

Alta eficiencia de desarrollo: Golang tiene una sintaxis concisa y una buena legibilidad del código. También proporciona muchas herramientas y marcos convenientes, que pueden mejorar la eficiencia del desarrollo y la calidad del código.

Comunidad activa de código abierto: Golang es un proyecto de código abierto con una gran comunidad de código abierto. Los miembros de la comunidad pueden compartir código, herramientas y experiencia, lo que hace que el ecosistema de Golang sea más próspero y estable.

16. Describa brevemente la función recursiva en Golang. ¿Cómo usar funciones recursivas?
Respuesta: Una función recursiva es una función que se llama a sí misma, que se puede usar para resolver algunos problemas recursivos, como el recorrido del árbol, el algoritmo divide y vencerás, la programación dinámica, etc. Al usar funciones recursivas, debe prestar atención a la profundidad de la recursividad. Una recursividad demasiado profunda puede causar problemas como el desbordamiento de la pila.

17. Describa brevemente el cierre en Golang. ¿Cómo usar los cierres?
Respuesta: El cierre se refiere a definir otra función dentro de una función, y la función interna puede acceder a las variables locales de la función externa. Los cierres se pueden utilizar para implementar algunas funciones avanzadas, como la programación funcional, el cálculo retrasado, el control de eventos, etc.

18. Describa brevemente el servidor HTTP en Golang. ¿Cómo usar el servidor HTTP?
Respuesta: Golang proporciona el paquete net/http para implementar servidores y clientes HTTP. Puede usar la función http.ListenAndServe para iniciar el servidor HTTP y usar la función http.HandleFunc para configurar el controlador de solicitudes HTTP.

19. ¿Cuáles son los usos de Go Hollow struct{}?
El tipo de estructura vacía struct{} en el lenguaje Go no ocupa ningún espacio de memoria y se denomina "estructura vacía". Este tipo especial tiene muchos usos en el lenguaje Go, estos son algunos de ellos:

Como semáforo (señal): un canal se puede usar para transferir datos, también se puede usar para transferir señales. Si un canal solo se usa para transmitir señales pero no datos, puede usar una estructura vacía como semáforo.

Marcador de posición: en algunas estructuras de datos, se debe ocupar un lugar, pero no es necesario almacenar los datos reales. En este caso, se puede utilizar una estructura vacía como marcador de posición.

Clave de colección: en el lenguaje Go, el mapa se puede utilizar para implementar la función de colección (conjunto). Cuando el valor de la clave no es importante y solo le importa si existe, puede usar una estructura vacía como la clave del mapa. Esto evita asignar espacio adicional y reduce el uso de memoria.

Parámetros de función: cuando no necesita pasar parámetros, puede usar una estructura vacía como parámetro de función para evitar la asignación de memoria innecesaria.

Marcadores de posición de estructura: al definir una estructura, a veces es necesario dejar espacio para los campos que se agregarán en el futuro. En este momento, puede usar una estructura vacía como marcador de posición para evitar modificar el código existente.

En resumen, la función principal de la estructura vacía es ocupar espacio sin almacenar datos, para realizar algunas funciones especiales. El uso de una estructura vacía puede evitar la asignación de memoria adicional y mejorar el rendimiento y la eficiencia del programa.

20. Dígame la diferencia entre el canal Go sin búfer y el canal con búfer.
En Go, los canales son un mecanismo importante para la comunicación y sincronización entre rutinas. Hay dos tipos de canales en Go: canales sin búfer y canales con búfer. La principal diferencia entre ellos es si el canal tiene un búfer.

Canal sin búfer Un canal sin búfer es un canal que no tiene capacidad para almacenar ningún valor antes de recibirlo. Al enviar datos a un canal sin búfer, la rutina del remitente se bloqueará hasta que la rutina del receptor reciba los datos del canal. Del mismo modo, cuando se reciben datos de un canal sin búfer, la corrutina del receptor se bloquea hasta que la corrutina del remitente envía datos al canal.
El canal sin búfer tiene un fuerte tiempo real y sincronización en la comunicación y sincronización entre rutinas, lo que puede garantizar el intercambio en tiempo real de los datos enviados y recibidos, pero si la velocidad del remitente y el receptor no coincide, se producirá un bloqueo. afectando el desempeño del programa.

Canales almacenados en búfer Un canal almacenado en búfer es un canal que puede almacenar una cierta cantidad de valor antes de recibirlo. Al enviar datos a un canal con búfer, si el búfer no está lleno, la corrutina del remitente puede enviar datos de inmediato al canal y continuar con la ejecución; si el búfer está lleno, la corrutina del remitente se bloqueará hasta que la corrutina del receptor haya obtenido los datos de el canal. De manera similar, cuando se reciben datos de un canal con búfer, si el búfer no está vacío, la rutina del receptor puede tomar inmediatamente los datos del canal y continuar con la ejecución; si el búfer está vacío, la rutina del receptor se bloqueará hasta que la rutina del remitente envíe datos a el canal.
Un canal almacenado en búfer puede evitar el bloqueo directo entre el remitente y el receptor, lo que puede mejorar el rendimiento del programa, pero causará retrasos en la transmisión de datos, lo que puede hacer que los datos recibidos sean inconsistentes con el pedido enviado, por lo que debe prestar atención. cuando se utiliza el problema de orden.

Guess you like

Origin blog.csdn.net/qq_44912603/article/details/129496737