Articles

Go (lenguaje de programación)

Posted by admin

Go está influenciado por C, pero con un énfasis en una mayor simplicidad y seguridad. El lenguaje consiste en:

  • Una sintaxis y un entorno que adoptan patrones más comunes en lenguajes dinámicos:
    • opcional declaración concisa de variables e inicialización a través de inferencia de tipos (x := 0 en lugar de int x = 0; o var x = 0;).
    • compilación rápida.
    • Gestión remota de paquetes (go get) y documentación de paquetes en línea.,
  • enfoques distintivos para problemas particulares:
    • primitivas de concurrencia integradas: procesos ligeros (goroutines), canales y la instrucciónselect.
    • Un sistema de interfaz en lugar de herencia virtual, y escriba incrustación en lugar de herencia no virtual.
    • Una cadena de herramientas que, por defecto, produce binarios nativos enlazados estáticamente sin dependencias externas.,
  • Un deseo de mantener la especificación del lenguaje lo suficientemente simple como para guardarla en la cabeza de un programador, en parte omitiendo características que son comunes en lenguajes similares.

SyntaxEdit

la sintaxis de Go incluye cambios de C destinados a mantener el código conciso y legible. Se introdujo un operador combinado de declaración / inicialización que permite al programador escribir i := 3 o s := "Hello, world!", sin especificar los tipos de variables utilizadas. Esto contrasta con C int i = 3; y const char *s = "Hello, world!";., Los puntos y comas todavía terminan las sentencias, pero están implícitos cuando se produce el final de una línea. Los métodos pueden devolver múltiples valores, y devolver un par result, err es la forma convencional en que un método indica un error a su llamador en Go. Go agrega sintaxis literales para inicializar parámetros de estructura por nombre y para inicializar mapas y sectores. Como alternativa al bucle de tres sentencias de C for, las expresiones de Go range permiten una iteración concisa sobre matrices, sectores, cadenas, mapas y canales.,

TypesEdit

para cada tipo T y cada constante entera no negativa n, hay un tipo de matriz denotado T; Las matrices de diferentes longitudes son, por lo tanto, de diferentes tipos. Los arrays dinámicos están disponibles como «slices», denotados T para algún tipo T. Estos tienen una longitud y una capacidad que especifican cuándo se necesita asignar nueva memoria para expandir el array. Varias rebanadas pueden compartir su memoria subyacente.los punteros

están disponibles para todos los tipos, y el tipo puntero a T se denota *T., La toma de direcciones y la indirección usan los operadores & y*, como en C, O ocurren implícitamente a través de la sintaxis de llamada al método o acceso a atributos. No hay aritmética puntero, excepto a través de la especial inseguro.Tipo de puntero en la biblioteca estándar.

para un par de tipos K, V, el tipo mapV es el tipo de tablas hash que asignan claves de tipo-K a valores de tipo-V. Las tablas Hash están integradas en el lenguaje, con sintaxis especial y funciones integradas. chan T es un canal que permite enviar valores de tipo T entre procesos go concurrentes.,

aparte de su soporte para interfaces, el sistema de tipos de Go es nominal: la palabra clave type se puede usar para definir un nuevo tipo con nombre, que es distinto de otros tipos con nombre que tienen el mismo diseño (en el caso de una estructura, los mismos miembros en el mismo orden). Algunas conversiones entre tipos (por ejemplo, entre varios tipos enteros) están predefinidas y agregar un nuevo tipo puede definir conversiones adicionales, pero las conversiones entre tipos con nombre siempre deben invocarse explícitamente., Por ejemplo, la palabra clave type se puede usar para definir un tipo para direcciones IPv4, basado en enteros sin signo de 32 bits:

type ipv4addr uint32

con esta definición de tipo, ipv4addr(x) interpreta el valor de uint32 x como una dirección IP. Simplemente asignar x a una variable de tipo ipv4addr es un error de tipo.

Las expresiones constantes pueden ser escritas o «sin escribir»; se les da un tipo cuando se asignan a una variable escrita si el valor que representan pasa una comprobación en tiempo de compilación.,

Los tipos de función se indican con la palabra clave func; toman cero o más parámetros y devuelven cero o más valores, todos los cuales se escriben. El parámetro y los valores de retorno determinan un tipo de función; por lo tanto, func(string, int32) (int, error) es el tipo de funciones que toman una cadena y un entero con signo de 32 bits, y devuelven un entero con signo (de ancho predeterminado) y un valor del tipo de interfaz integrado error.

cualquier tipo con nombre tiene un conjunto de métodos asociado a él., El ejemplo de dirección IP anterior se puede ampliar con un método para verificar si su valor es un estándar conocido:

// ZeroBroadcast reports whether addr is 255.255.255.255.func (addr ipv4addr) ZeroBroadcast() bool { return addr == 0xFFFFFFFF}

debido a la tipificación nominal, esta definición de método agrega un método a ipv4addr, pero no en uint32. Aunque los métodos tienen una definición especial y una sintaxis de llamada, no hay un tipo de método distinto.

Interface systemEdit

Go proporciona dos características que reemplazan la herencia de clases.

el primero es la incrustación, que puede verse como una forma automatizada de composición o delegación.,: 255

el segundo son sus interfaces, que proporciona polimorfismo en tiempo de ejecución.: 266 las Interfaces son una clase de tipos y proporcionan una forma limitada de tipificación estructural en el sistema de tipo nominal de Go. Un objeto que es de un tipo de interfaz es también de otro tipo, al igual que los objetos C++ que son simultáneamente de una clase base y derivada. Las interfaces Go fueron diseñadas después de protocolos del lenguaje de programación Smalltalk. Múltiples fuentes usan el término duck typing cuando describen interfaces Go., Aunque el término duck typing no está definido con precisión y, por lo tanto, no es incorrecto, generalmente implica que la conformidad del tipo no se verifica estáticamente. Dado que la conformidad con una interfaz Go es comprobada estáticamente por el compilador de Go (excepto cuando se realiza una aserción de Tipo), los autores de Go prefieren el término tipificación estructural.

La definición de un tipo de interfaz enumera los métodos requeridos por nombre y tipo. Cualquier objeto de tipo T para el que existan funciones que coincidan con todos los métodos requeridos de interfaz tipo I es un objeto de tipo I también. La definición de tipo T no necesita (y no puede) identificar el tipo I., Por ejemplo, si Forma, Cuadrado y círculo se definen como

entonces tanto un cuadrado como un círculo son implícitamente una forma y se pueden asignar a una variable con forma.: 263-268 en lenguaje formal, el sistema de interfaz de Go proporciona mecanografía estructural en lugar de nominal. Las Interfaces pueden incrustar otras interfaces con el efecto de crear una interfaz combinada que se satisfaga exactamente con los tipos que implementan la interfaz incrustada y cualquier método que agregue la interfaz recién definida.,: 270

La biblioteca estándar Go utiliza interfaces para proporcionar genericidad en varios lugares, incluido el sistema de entrada / salida que se basa en los conceptos de lector y escritor.: 282-283

Además de llamar a métodos a través de interfaces, Go permite convertir valores de interfaz a otros tipos con una comprobación de tipo en tiempo de ejecución. Las construcciones de lenguaje para hacerlo son la afirmación de tipo, que comprueba contra un solo tipo potencial, y el interruptor de tipo, que comprueba contra varios tipos.,

la interfaz vacía interface{} es un caso base importante porque puede referirse a un elemento de cualquier tipo concreto. Es similar a la clase Object en Java o C# y se satisface con cualquier tipo, incluidos los tipos integrados como int.: 284 el código que usa la interfaz vacía no puede simplemente llamar a métodos (u operadores incorporados) en el objeto referido, pero puede almacenar el valor interface{}, tratar de convertirlo a un tipo más útil a través de una aserción de tipo o un interruptor de tipo, o inspeccionarlo con el paquete reflect de Go., Debido a que interface{} puede referirse a cualquier valor, es una forma limitada de escapar de las restricciones de escritura estática, como void* en C pero con comprobaciones de tipo adicionales en tiempo de ejecución.

el tipo interface{} se puede usar para modelar datos estructurados de cualquier esquema arbitrario en Go, como datos JSON o YAML, representándolo como un mapinterface{}(map of string to empty interface). Esto describe datos recursivamente en forma de diccionario con claves de cadena y valores de cualquier tipo.,

Los valores de la interfaz se implementan utilizando puntero a datos y un segundo puntero a información de tipo en tiempo de ejecución. Al igual que algunos otros tipos implementados usando punteros en Go, los valores de la interfaz son nil si no está inicializado.

Package systemEdit

en el sistema de paquetes de Go, cada paquete tiene una ruta (por ejemplo, "compress/bzip2" o "golang.org/x/net/html") y un nombre (por ejemplo, bzip2 o html)., Las referencias a las definiciones de otros paquetes siempre deben ir precedidas por el nombre del otro paquete, y solo los nombres en mayúscula de otros paquetes son accesibles: io.Reader es público pero bzip2.reader no lo es. El comando go get puede recuperar paquetes almacenados en un repositorio remoto y se anima a los desarrolladores a desarrollar paquetes dentro de una ruta base correspondiente a un repositorio de origen (como por ejemplo.,com / user_name / package_name) para reducir la probabilidad de colisión de nombres con futuras adiciones a la biblioteca estándar u otras bibliotecas externas.

Existen propuestas para introducir una solución de gestión de paquetes adecuada para Go similar a CPAN para Perl o el sistema de carga de Rust o el sistema npm de Node.

Concurrency: goroutines and channelsEdit

El lenguaje Go tiene instalaciones integradas, así como soporte de biblioteca, para escribir programas concurrentes., La concurrencia no solo se refiere al paralelismo de la CPU, sino también a la asincronía: permitir que se ejecuten operaciones lentas como una base de datos o una lectura de red mientras el programa realiza otro trabajo, como es común en los servidores basados en eventos.

la construcción de concurrencia primaria es la goroutine, un tipo de proceso ligero. Una llamada a función prefijada con la palabra clave go inicia una función en una nueva goroutine., La especificación del lenguaje no especifica cómo deben implementarse las goroutinas, pero las implementaciones actuales multiplexan las goroutinas de un proceso Go en un conjunto más pequeño de subprocesos del sistema operativo, similar a la programación realizada en Erlang.: 10

mientras que un paquete de biblioteca estándar con la mayoría de las estructuras de control de concurrencia clásicas (bloqueos mutex, etc.) está disponible,:151-152 programas simultáneos idiomáticos en su lugar prefieren canales, que proporcionan enviar mensajes entre goroutines., Los buffers opcionales almacenan los mensajes en orden FIFO: 43 y permiten que el envío de goroutines proceda antes de que se reciban sus mensajes.

Los canales se escriben, de modo que un canal de tipo chan T solo se puede usar para transferir mensajes de tipo T. se usa una sintaxis especial para operar en ellos; <-ch es una expresión que hace que el goroutine ejecutante se bloquee hasta que un valor entre en el canal ch, mientras que ch <- x envía el valor x (posiblemente bloqueando hasta que otro goroutine valor)., La instrucción SELECT integrada, similar a un conmutador, se puede usar para implementar la comunicación sin bloqueo en múltiples canales; Vea un ejemplo a continuación. Go tiene un modelo de memoria que describe cómo goroutines debe usar canales u otras operaciones para compartir datos de forma segura.

la existencia de conjuntos de canales se aparta de los lenguajes concurrentes de estilo modelo actor como Erlang, donde los mensajes se dirigen directamente a los actores (correspondientes a goroutines)., El estilo de actor se puede simular en Go manteniendo una correspondencia uno a uno entre goroutines y canales, pero el lenguaje permite que varios goroutines compartan un canal o que un solo goroutine envíe y reciba en varios canales.: 147

desde estas herramientas se pueden construir construcciones concurrentes como grupos de trabajo, canalizaciones (en las que, por ejemplo, un archivo se descomprime y analiza a medida que se descarga), llamadas en segundo plano con tiempo de espera, llamadas paralelas «fan-out» a un conjunto de servicios, y otros., Los canales también han encontrado usos más alejados de la noción habitual de comunicación interproceso, como servir como una lista segura de búferes reciclados, implementar corrutinas (que ayudaron a inspirar el nombre goroutine) e implementar iteradores.

LAS CONVENCIONES estructurales relacionadas con la concurrencia de Go (canales y entradas de canales alternativos) se derivan del modelo de procesos secuenciales de comunicación de Tony Hoare., A diferencia de lenguajes de programación concurrentes anteriores como Occam o Limbo (un lenguaje en el que trabajó el co-diseñador de Go Rob Pike), Go no proporciona ninguna noción incorporada de concurrencia segura o verificable. Si bien el modelo de procesos de comunicación es favorecido en Go, no es el único: todas las goroutinas en un programa comparten un solo espacio de direcciones. Esto significa que los objetos mutables y los punteros pueden ser compartidos entre goroutines; ver § falta de seguridad de la condición de raza, a continuación.,

idoneidad para la programación paralelaeditar

aunque las características de concurrencia de Go no están dirigidas principalmente al procesamiento paralelo, se pueden usar para programar máquinas multiprocesadoras de memoria compartida. Se han realizado varios estudios sobre la eficacia de este enfoque. Uno de estos estudios comparó el tamaño (en líneas de código) y la velocidad de los programas escritos por un programador experimentado no familiarizado con el lenguaje y las correcciones a estos programas por un experto en Go (del equipo de desarrollo de Google), haciendo lo mismo para Chapel, Cilk e Intel TBB., El estudio encontró que el no experto tendía a escribir algoritmos de divide y vencerás con una instrucción go por recursión, mientras que el experto escribía programas de distribución-trabajo-sincronización usando una goroutine por procesador. Los programas de los expertos eran generalmente más rápidos, pero también Más largos.

falta de seguridad en las condiciones de la carreraEditar

no hay restricciones sobre cómo los gorroutines acceden a los datos compartidos, lo que hace posible las condiciones de la carrera., Específicamente, a menos que un programa se sincronice explícitamente a través de canales u otros medios, las Escrituras de un goroutine podrían ser en parte, en su totalidad o no ser visibles para otro, a menudo sin garantías sobre el orden de las Escrituras. Además, las estructuras de datos internas de Go, como los valores de interfaz, los encabezados de corte, las tablas hash y los encabezados de cadena, no son inmunes a las condiciones de carrera, por lo que la seguridad de tipo y memoria puede violarse en programas multihilo que modifican instancias compartidas de esos tipos sin sincronización., En lugar de soporte de lenguaje, la programación concurrente segura se basa en convenciones; por ejemplo, Chisnall recomienda un modismo llamado «alias XOR mutable», lo que significa que pasar un valor mutable (o puntero) sobre un canal indica una transferencia de propiedad sobre el valor a su receptor.: 155

BinariesEdit

el enlazador en la cadena de herramientas gc crea binarios enlazados estáticamente de forma predeterminada, por lo tanto, todos los binarios de Go incluyen el tiempo de ejecución de Go.,

OmissionsEdit

Go omite deliberadamente ciertas características comunes en otros lenguajes, incluyendo herencia (implementación), programación genérica, aserciones, aritmética de punteros, conversiones de tipos implícitas, uniones sin etiquetar y uniones etiquetadas. Los diseñadores agregaron solo las instalaciones en las que los tres estuvieron de acuerdo.,

de las características del lenguaje omitidas, los diseñadores argumentan explícitamente en contra de las aserciones y la aritmética de punteros, mientras defienden la opción de omitir la herencia de tipos como un lenguaje más útil, alentando en su lugar el uso de interfaces para lograr el despacho dinámico y la composición para reutilizar el código. De hecho, la composición y la delegación están en gran medida automatizadas por la incrustación de estructuras; según los investigadores Schmager et al., esta característica » tiene muchos de los inconvenientes de la herencia: afecta la interfaz pública de los objetos, no es de grano fino (i.,e, sin control a nivel de método sobre la incrustación), los métodos de objetos incrustados no se pueden ocultar, y es estático», por lo que «no es obvio» Si los programadores lo usarán en exceso en la medida en que los programadores en otros lenguajes tienen fama de abusar de la herencia.

los diseñadores expresan una apertura a la programación genérica y notan que las funciones incorporadas son de hecho genéricas de tipo, pero estas son tratadas como casos especiales; Pike llama a esto una debilidad que en algún momento puede ser cambiada. El equipo de Google construyó al menos un compilador para un dialecto experimental de Go con genéricos, pero no lo liberó., También están abiertos a estandarizar formas de aplicar la generación de código. En junio de 2020, se publicó un nuevo borrador del documento de diseño, que agregaría la sintaxis necesaria para declarar funciones y tipos genéricos. Se proporcionó una herramienta de traducción de código go2go para permitir a los usuarios probar la nueva sintaxis, junto con una versión habilitada para genéricos Del Go Playground en línea.,

inicialmente omitido, el mecanismo tipo excepción panic/recover fue finalmente añadido, que los autores de Go aconsejan usar para errores irrecuperables, como aquellos que deberían detener una solicitud de programa o servidor completa, o como un acceso directo para propagar errores en la pila dentro de un paquete (pero no a través de los límites del paquete; allí, los retornos de error son la API estándar).

Leave A Comment