Go es un lenguaje de programación de alto nivel compilado y tipado estáticamente diseñado en Google [12] por Robert Griesemer , Rob Pike y Ken Thompson . [13] Es sintácticamente similar a C , pero también tiene seguridad de memoria , recolección de basura , tipado estructural , [7] y concurrencia estilo CSP . [14] A menudo se le conoce como Golang debido a su antiguo nombre de dominio, pero su nombre propio es Go. [15] golang.org
Hay dos implementaciones principales:
Un compilador de fuente a fuente de terceros , GopherJS, [21] compila Go to JavaScript para el desarrollo web front-end .
Go fue diseñado en Google en 2007 para mejorar la productividad de la programación en una era de máquinas multinúcleo conectadas en red y grandes bases de código . [22] Los diseñadores querían abordar las críticas a otros lenguajes utilizados en Google, pero manteniendo sus características útiles: [23]
Sus diseñadores estaban motivados principalmente por su aversión compartida hacia C++ . [25] [26] [27]
Go se anunció públicamente en noviembre de 2009, [28] y la versión 1.0 se lanzó en marzo de 2012. [29] [30] Go se usa ampliamente en producción en Google [31] y en muchas otras organizaciones y proyectos de código abierto.
La mascota Gopher se introdujo en 2009 para el lanzamiento de código abierto del lenguaje. El diseño, de Renée French , tomado de un c. 2000 Promoción WFMU . [32]
En noviembre de 2016, los diseñadores tipográficos Charles Bigelow y Kris Holmes lanzaron las fuentes Go y Go Mono específicamente para su uso en el proyecto Go. Go es un humanista sans-serif que se parece a Lucida Grande , y Go Mono es monoespaciado . Ambas fuentes se adhieren al juego de caracteres WGL4 y fueron diseñadas para ser legibles con una altura x grande y formas de letras distintas . Tanto Go como Go Mono se adhieren al estándar DIN 1450 al tener un cero recortado, minúsculas l
con cola y mayúsculas I
con serifas. [33] [34]
En abril de 2018, el diseñador de la marca Adam Smith rediseñó el logotipo original. El nuevo logotipo es un GO moderno y estilizado inclinado hacia la derecha con líneas de corriente al final. (La mascota Gopher siguió siendo la misma. [35] )
La falta de soporte para programación genérica en las versiones iniciales de Go generó considerables críticas. [36] Los diseñadores expresaron una apertura a la programación genérica y señalaron que las funciones integradas eran de hecho genéricas, pero se tratan como casos especiales; Pike llamó a esto una debilidad que podría cambiarse en algún momento. [37] El equipo de Google creó al menos un compilador para un dialecto Go experimental con genéricos, pero no lo lanzó. [38]
En agosto de 2018, los principales contribuyentes de Go publicaron borradores de diseños para programación genérica y manejo de errores y pidieron a los usuarios que enviaran comentarios. [39] [40] Sin embargo, la propuesta de manejo de errores finalmente fue abandonada. [41]
En junio de 2020, se publicó un nuevo borrador de documento de diseño [42] que agregaría la sintaxis necesaria a Go 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 genérica del Go Playground en línea. [43]
Finalmente se agregaron genéricos a Go en la versión 1.18. [44]
Go 1 garantiza compatibilidad [45] para la especificación del lenguaje y la mayor parte de la biblioteca estándar. Todas las versiones hasta la actual Go 1.22 [46] han mantenido esta promesa.
Cada versión principal de Go es compatible hasta que haya dos versiones principales más nuevas. [47]
Go está influenciado por C (especialmente el dialecto Plan 9 [48] [ verificación fallida – ver discusión ] ), pero con énfasis en una mayor simplicidad y seguridad. Consiste en:
x := 0
var x int = 0;
var x = 0;
go get
) [51] y documentación de paquetes en línea [52]select
declaraciónLa sintaxis de Go incluye cambios respecto a 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 o sin especificar los tipos de variables utilizadas. Esto contrasta con C y .i := 3
s := "Hello, world!"
int i = 3;
const char *s = "Hello, world!";
Los puntos y coma todavía terminan las declaraciones; [b] pero están implícitos cuando ocurre el final de una línea. [C]
Los métodos pueden devolver múltiples valores, y devolver un par es la forma convencional en que un método indica un error a quien lo llama en Go. [d] Go agrega sintaxis literal para inicializar parámetros de estructura por nombre y para inicializar mapas y sectores . Como alternativa al bucle de tres declaraciones de C, las expresiones de Go permiten una iteración concisa sobre matrices, sectores, cadenas, mapas y canales. [56]result, err
for
range
Go tiene varios tipos integrados, incluidos los numéricos ( byte , int64 , float32 , etc.), booleanos y cadenas de bytes ( string ). Las cadenas son inmutables; Los operadores y palabras clave integrados (en lugar de funciones) proporcionan concatenación, comparación y codificación/decodificación UTF-8 . [57] Los tipos de registros se pueden definir con la palabra clave struct . [58]
Para cada tipo T y cada constante entera no negativa n , existe un tipo de matriz denominado [ n ] T ; las matrices de diferentes longitudes son, por tanto, de diferentes tipos. Las matrices dinámicas están disponibles como "porciones", denominadas [] T para algún tipo T . Estos tienen una longitud y una capacidad que especifican cuándo se debe asignar nueva memoria para expandir la matriz. Varias porciones pueden compartir su memoria subyacente. [37] [59] [60]
Los punteros están disponibles para todos los tipos y el tipo de puntero a T se denomina * T . La toma de direcciones y la dirección indirecta utilizan los operadores & y * , como en C, o ocurren implícitamente a través de la llamada al método o la sintaxis de acceso al atributo. [61] [62] No hay aritmética de punteros, [e] excepto a través del tipo especial unsafe.Pointer en la biblioteca estándar. [63]
Para un par de tipos K , V , el tipo map[ K ] V es el tipo que asigna claves de tipo K a valores de tipo V , aunque la especificación del lenguaje de programación Go no ofrece ninguna garantía de rendimiento ni requisitos de implementación para los tipos de mapas. 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. [64]
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 los distintos tipos de enteros) están predefinidas y agregar un nuevo tipo puede definir conversiones adicionales, pero las conversiones entre tipos nombrados siempre deben invocarse explícitamente. [65] Por ejemplo, la palabra clave type se puede utilizar para definir un tipo para direcciones IPv4 , basándose en enteros sin signo de 32 bits de la siguiente manera:
escriba ipv4addr uint32
Con esta definición de tipo, ipv4addr(x) interpreta el valor x de uint32 como una dirección IP. Simplemente asignar x a una variable de tipo ipv4addr es un error de tipo. [66]
Las expresiones constantes pueden estar escritas o "sin escribir"; se les asigna un tipo cuando se asignan a una variable escrita si el valor que representan pasa una verificación en tiempo de compilación. [67]
Los tipos de funciones se indican mediante la palabra clave func ; toman cero o más parámetros y devuelven cero o más valores, todos los cuales están escritos. Los valores de parámetro y 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 incorporado. error . [68]
Cualquier tipo con nombre tiene un conjunto de métodos asociado. 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 informa si la dirección es 255.255.255.255. func ( dirección ipv4addr ) ZeroBroadcast () bool { dirección de retorno == 0xFFFFFFFF }
Debido a la tipificación nominal, esta definición de método agrega un método a ipv4addr , pero no a uint32 . Si bien los métodos tienen una definición y una sintaxis de llamada especiales, no existe un tipo de método distinto. [69]
Go proporciona dos funciones que reemplazan la herencia de clases . [ cita necesaria ]
El primero es la incrustación , que puede verse como una forma automatizada de composición . [70]
El segundo son sus interfaces , que proporcionan polimorfismo en tiempo de ejecución . [71] : 266 Las interfaces son una clase de tipos y proporcionan una forma limitada de tipificación estructural en el sistema de tipos nominal de Go. Un objeto que es de un tipo de interfaz también es de otro tipo, al igual que los objetos C++ que son simultáneamente de una clase base y derivada. Las interfaces Go se diseñaron a partir de protocolos del lenguaje de programación Smalltalk. [72] Múltiples fuentes utilizan el término tipificación pato al describir las interfaces Go. [73] [74] Aunque el término tipificación de pato 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. Debido a que el compilador de Go verifica estáticamente la conformidad con una interfaz de Go (excepto cuando se realiza una afirmación de tipo), los autores de Go prefieren el término tipado estructural . [75]
La definición de un tipo de interfaz enumera los métodos requeridos por nombre y tipo. Cualquier objeto de tipo T para el cual existan funciones que coincidan con todos los métodos requeridos de la interfaz tipo I también es un objeto de tipo I. 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
importar "matemáticas" tipo Interfaz de forma { Área () float64 } type Square struct { // Nota: no hay declaración de "implementos" en el lado float64 } func ( cuadrado cuadrado ) Área ( ) float64 { retorno cuadrado . lado * cuadrado . lado } type Circle struct { // No hay declaración de "implementos" aquí tampoco radio float64 } func ( c Círculo ) Área () float64 { return math . Pi * matemáticas . Pow ( c . radio , 2 ) }
entonces tanto un Cuadrado como un Círculo son implícitamente una Forma y pueden asignarse a una variable de tipo Forma . [71] : 263–268 En lenguaje formal, el sistema de interfaz de Go proporciona tipificación estructural en lugar de nominal . Las interfaces pueden incorporar otras interfaces con el efecto de crear una interfaz combinada que se satisface exactamente con los tipos que implementan la interfaz incorporada y cualquier método que agregue la interfaz recién definida. [71] : 270
La biblioteca estándar Go utiliza interfaces para proporcionar genérica en varios lugares, incluido el sistema de entrada/salida que se basa en los conceptos de Reader y Writer . [71] : 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 verificación de tipo en tiempo de ejecución. Las construcciones del lenguaje para hacerlo son el tipo de afirmación , [76] que compara con un único tipo potencial:
var shp Forma = Cuadrado { 5 } cuadrado , ok := shp .( Cuadrado ) // Afirma el tipo Cuadrado en shp, debería funcionar si está bien { fmt . Printf ( "%#v\n" , cuadrado ) } else { fmt . Println ( "No se puede imprimir la forma como cuadrado" ) }
y el interruptor de tipo , [77] que compara múltiples tipos: [ cita necesaria ]
func ( cuadrado cuadrado ) Diagonal ( ) float64 { retorno cuadrado . lado * matemáticas . Sqrt2 } func ( c Círculo ) Diámetro () float64 { return 2 * c . radio } func LongestContainedLine ( shp Shape ) float64 { switch v := shp .( tipo ) { case Square : return v . Diagonal () // O, con aserción de tipo, shp.(Square).Diagonal() case Circle : return v . Diámetro () // O, con aserción de tipo, shp.(Circle).Diameter() predeterminado : return 0 // En la práctica, esto debería manejarse con errores } }
La interfaz vacía es un caso base importante porque puede hacer referencia 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 . [71] : 284 El código que utiliza la interfaz vacía no puede simplemente llamar a métodos (u operadores integrados) en el objeto al que se hace referencia, pero puede almacenar el valor, intentar convertirlo a un tipo más útil mediante una aserción de tipo o un tipo. cambie o inspeccione con el paquete de Go. [78] Debido a que puede hacer referencia a cualquier valor, es una forma limitada de escapar de las restricciones del tipado estático, como en C pero con comprobaciones de tipo adicionales en tiempo de ejecución. [ cita necesaria ]interface{}
interface{}
reflect
interface{}
void*
El tipo se puede utilizar para modelar datos estructurados de cualquier esquema arbitrario en Go, como datos JSON o YAML , representándolos como (mapa de cadena a interfaz vacía). Esto describe recursivamente datos en forma de diccionario con claves de cadena y valores de cualquier tipo. [79]interface{}
map[string]interface{}
Los valores de la interfaz se implementan utilizando un puntero a datos y un segundo puntero a información de tipo de tiempo de ejecución. [80] Al igual que otros tipos implementados utilizando punteros en Go, los valores de la interfaz nil
no están inicializados. [81]
Desde la versión 1.18, Go admite código genérico utilizando tipos parametrizados. [82]
Las funciones y tipos ahora tienen la capacidad de ser genéricos mediante parámetros de tipo. Estos parámetros de tipo se especifican entre corchetes, justo después del nombre de la función o del tipo. [83] El compilador transforma la función o tipo genérico en no genérico sustituyendo argumentos de tipo por los parámetros de tipo proporcionados, ya sea explícitamente por el usuario o por inferencia de tipo por parte del compilador. [84] Este proceso de transformación se conoce como creación de instancias de tipo. [85]
Las interfaces ahora pueden definir un conjunto de tipos (conocido como conjunto de tipos) utilizando |
el operador (Unión), así como un conjunto de métodos. Estos cambios se realizaron para admitir restricciones de tipo en el código genérico. Para una función o tipo genérico, se puede considerar una restricción como el tipo de argumento de tipo: un metatipo. Esta nueva ~T
sintaxis será el primer uso ~
como token en Go. ~T
significa el conjunto de todos los tipos cuyo tipo subyacente es T
. [86]
tipo Número interfaz { ~ int | ~ flotador64 | ~ flotador32 | ~ int32 | ~ int64 } func Agregar [ Número T ]( nums ... T ) T { var suma T para _ , v := rango números { suma += v } devolver suma } func main () { add := Add [ int ] // Escribe instanciación println ( add ( 1 , 2 , 3 , 4 , 5 )) // 15 res := Agregar ( 1.1 , 2.2 , 3.3 , 4.4 , 5.5 ) // Inferencia de tipos println ( res ) // +1.650000e+001 }
Go usa la iota
palabra clave para crear constantes enumeradas. [87]
escriba ByteSize float64 const ( _ = iota // ignora el primer valor asignando un identificador en blanco KB ByteSize = 1 << ( 10 * iota ) MB GB )
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 tener como prefijo el nombre del otro paquete, y solo se puede acceder a los nombres en mayúsculaio.Reader
de otros paquetes: es público pero bzip2.reader
no lo es. [88] El go get
comando puede recuperar paquetes almacenados en un repositorio remoto [89] y se anima a los desarrolladores a desarrollar paquetes dentro de una ruta base correspondiente a un repositorio de origen (como ejemplo.com/nombre_usuario/nombre_paquete) para reducir la probabilidad de colisión de nombres. con futuras adiciones a la biblioteca estándar u otras bibliotecas externas. [90]
El lenguaje Go tiene funciones integradas, así como soporte de biblioteca, para escribir programas concurrentes . La concurrencia se refiere no solo al paralelismo de la CPU, sino también a la asincronía : permitir que operaciones lentas como una base de datos o lectura de red se ejecuten mientras el programa realiza otro trabajo, como es común en los servidores basados en eventos. [91]
La principal construcción de concurrencia es la gorutina , un tipo de hilo verde . [92] : 280–281 Una llamada de función con el prefijo de la go
palabra clave inicia una función en una nueva rutina. La especificación del lenguaje no especifica cómo se deben implementar las gorutinas, pero las implementaciones actuales multiplexan las gorutinas de un proceso Go en un conjunto más pequeño de subprocesos del sistema operativo , similar a la programación realizada en Erlang . [93] : 10
Si bien está disponible un paquete de biblioteca estándar que presenta la mayoría de las estructuras clásicas de control de concurrencia ( bloqueos mutex , etc.), [93] : 151–152 los programas idiomáticos concurrentes prefieren canales , que envían mensajes entre gorutinas. [94] Los buffers opcionales almacenan mensajes en orden FIFO [95] : 43 y permiten que el envío de rutinas continúe antes de que se reciban sus mensajes. [92] : 233
Los canales están tipificados, de modo que un canal de tipo chan T solo puede usarse para transferir mensajes de tipo T. Se utiliza una sintaxis especial para operar con ellos; <-ch es una expresión que hace que la gorutina en ejecución se bloquee hasta que llegue un valor a través del canal ch , mientras que ch <- x envía el valor x (posiblemente bloqueándose hasta que otra gorutina reciba el valor). La declaración de selección tipo interruptor incorporada se puede utilizar para implementar comunicación sin bloqueo en múltiples canales; vea a continuación un ejemplo. Go tiene un modelo de memoria que describe cómo las gorutinas deben usar canales u otras operaciones para compartir datos de forma segura. [96]
La existencia de canales no distingue por sí sola a Go de los lenguajes concurrentes estilo modelo de actor como Erlang, donde los mensajes se dirigen directamente a los actores (correspondientes a gorutinas). En el modelo de actor, los canales son en sí mismos actores, por lo tanto, dirigirse a un canal sólo significa dirigirse a un actor. El estilo del actor se puede simular en Go manteniendo una correspondencia uno a uno entre gorutinas y canales, pero el lenguaje permite que múltiples gorutinas compartan un canal o que una sola gorutina envíe y reciba en múltiples canales. [93] : 147
A partir de estas herramientas se pueden crear construcciones concurrentes como grupos de trabajadores, 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 "distribuidas" a un conjunto de servicios y otras. . [97] Los canales también han encontrado usos más alejados de la noción habitual de comunicación entre procesos, como servir como una lista de buffers reciclados seguros para la concurrencia, [98] implementar corrutinas (que ayudaron a inspirar el nombre goroutine ), [99] e implementar iteradores . [100]
Las convenciones estructurales de Go relacionadas con la concurrencia ( 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 codiseñador de Go, Rob Pike), [101] Go no proporciona ninguna noción integrada de concurrencia segura o verificable. [102] Si bien el modelo de procesos de comunicación es el preferido en Go, no es el único: todas las gorutinas de un programa comparten un único espacio de direcciones. Esto significa que los objetos mutables y los punteros se pueden compartir entre gorutinas; consulte § Falta de seguridad en la carrera de datos, a continuación.
Aunque las características de concurrencia de Go no están dirigidas principalmente al procesamiento paralelo , [91] pueden usarse para programar máquinas multiprocesador de memoria compartida . Se han realizado varios estudios sobre la eficacia de este enfoque. [103] Uno de estos estudios comparó el tamaño (en líneas de código ) y la velocidad de programas escritos por un programador experimentado que no estaba familiarizado con el lenguaje y las correcciones a estos programas realizadas por un experto en Go (del equipo de desarrollo de Google), haciendo lo mismo para Capilla , Cilk e Intel TBB . El estudio encontró que los no expertos tendían a escribir algoritmos de divide y vencerás con una declaración por recursión, mientras que los expertos escribían programas de distribución, trabajo y sincronización usando una rutina por núcleo de procesador. Los programas de los expertos solían ser más rápidos, pero también más largos. [104]
El enfoque de Go hacia la concurrencia se puede resumir como "no comunicarse compartiendo memoria; comparta memoria comunicándose". [105] No existen restricciones sobre cómo las gorutinas acceden a los datos compartidos, lo que hace posibles las carreras de datos . Específicamente, a menos que un programa se sincronice explícitamente a través de canales u otros medios, las escrituras de una rutina pueden ser parcial, totalmente o no visibles para otra, a menudo sin garantías sobre el orden de las escrituras. [102] Además, las estructuras de datos internas de Go, como valores de interfaz, encabezados de sectores, tablas hash y encabezados de cadenas, no son inmunes a las carreras de datos, por lo que la seguridad de tipo y memoria puede violarse en programas multiproceso que modifican instancias compartidas de esos tipos sin sincronización. [106] [107] En lugar de soporte de lenguaje, la programación concurrente segura se basa en convenciones; por ejemplo, Chisnall recomienda un modismo llamado "aliases 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. [93] : 155 La cadena de herramientas de gc tiene un detector de carrera de datos opcional que puede verificar el acceso no sincronizado a la memoria compartida durante el tiempo de ejecución desde la versión 1.1, [108] además, también se incluye un detector de carrera de mejor esfuerzo de forma predeterminada desde la versión 1.6 de gc tiempo de ejecución para acceder al map
tipo de datos. [109]
El vinculador en la cadena de herramientas gc crea archivos binarios vinculados estáticamente de forma predeterminada; por lo tanto, todos los archivos binarios de Go incluyen el tiempo de ejecución de Go. [110] [111]
Go omite deliberadamente ciertas características comunes en otros lenguajes, incluida la herencia (implementación) , las afirmaciones , la aritmética de punteros [f] , las conversiones de tipos implícitas [e] , las uniones sin etiquetar , [g] y las uniones etiquetadas . [h] Los diseñadores agregaron solo aquellas instalaciones en las que los tres estuvieron de acuerdo. [114]
De las características del lenguaje omitidas, los diseñadores argumentan explícitamente en contra de las afirmaciones y la aritmética de punteros, mientras defienden la opción de omitir la herencia de tipos como un lenguaje más útil, fomentando en su lugar el uso de interfaces para lograr el despacho dinámico [i] y la composición para reutilizar el código. De hecho , la composición y la delegación están en gran medida automatizadas mediante 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 detallada (es decir, no hay control a nivel de método sobre la incrustación), los métodos de los objetos incrustados no se pueden ocultar y es estático ", lo que hace que "no sea obvio" si los programadores lo usarán en exceso en la medida en que los programadores de otros lenguajes tienen fama de abusar de la herencia. [70]
El manejo de excepciones se omitió inicialmente en Go debido a la falta de un "diseño que dé un valor proporcional a la complejidad". [115] Se propuso un mecanismo de pánico / recuperación similar a una excepción que evita la estructura de control habitual [116] y se publicó en la instantánea del 30 de marzo de 2010. [117] Los autores de Go recomiendan usarlo para errores irrecuperables, como aquellos que deberían detener un programa completo o una solicitud del servidor, o como un atajo para propagar errores en la pila dentro de un paquete. [118] [119] Más allá de los límites del paquete, Go incluye un tipo de error canónico y las devoluciones de valores múltiples que utilizan este tipo son el lenguaje estándar. [13]try-catch
Los autores de Go hicieron un esfuerzo sustancial para influir en el estilo de los programas de Go:
gofmt
. Utiliza pestañas para sangría y espacios en blanco para alineación. La alineación supone que un editor utiliza una fuente de ancho fijo. [120] golint
realiza comprobaciones de estilo adicionales automáticamente, pero los mantenedores de Go lo han dejado en desuso y lo han archivado. [121]godoc
), [122] pruebas ( go test
), construcción ( go build
), administración de paquetes ( go get
), etc.map
estilo Java ) tiende a fomentar un estilo de programación particular, explícito, concreto e imperativo.try
finally
La distribución principal de Go incluye herramientas para crear , probar y analizar código:
go build
, que crea binarios de Go utilizando solo información de los archivos fuente, sin archivos MAKE separadosgo test
, para pruebas unitarias y microbenchmarks, así como fuzzinggo fmt
, para formatear el códigogo install
, para recuperar e instalar paquetes remotosgo vet
, un analizador estático que busca posibles errores en el códigogo run
, un atajo para crear y ejecutar códigogodoc
, para mostrar documentación o servirla a través de HTTPgorename
, para cambiar el nombre de variables, funciones, etc. de forma segurago generate
, una forma estándar de invocar generadores de códigogo mod
, para crear un nuevo módulo, agregar dependencias, actualizar dependencias, etc.También incluye soporte para la creación de perfiles y depuración , capacidades de fuzzing para detectar errores, instrumentación en tiempo de ejecución (por ejemplo, para rastrear las pausas de recolección de basura ) y un detector de carrera de datos .
Otra herramienta mantenida por el equipo de Go pero que no está incluida en las distribuciones de Go es gopls
, un servidor de idiomas que proporciona funciones IDE , como la finalización inteligente de código, a editores compatibles con Language Server Protocol . [128]
Un ecosistema de herramientas de terceros se suma a la distribución estándar, como gocode
, que permite el autocompletado de código en muchos editores de texto, goimports
que agrega/elimina automáticamente importaciones de paquetes según sea necesario y errcheck
que detecta código que podría ignorar errores sin querer.
paquete principal importar "fmt" func principal () { fmt . Println ( "hola mundo" ) }
donde "fmt" es el paquete para E/S formateadas , similar a la entrada/salida del archivo C de C. [129]
El siguiente programa simple demuestra las características de concurrencia de Go para implementar un programa asincrónico. Lanza dos subprocesos ligeros ("goroutines"): uno espera a que el usuario escriba algo de texto, mientras que el otro implementa un tiempo de espera. La declaración select espera a que cualquiera de estas rutinas envíe un mensaje a la rutina principal y actúa sobre el primer mensaje que llega (ejemplo adaptado del libro de David Chisnall). [93] : 152
paquete principal importar ( "fmt" "hora" ) func readword ( cadena ch chan ) { fmt . Println ( "Escribe una palabra y luego presiona Enter." ) var word string fmt . Scanf ( "%s" y palabra ) ch < - palabra } func tiempo de espera ( t chan bool ) { tiempo . Dormir ( 5 * tiempo . Segundo ) t <- false } func main () { t : = hacer ( chan bool ) pasar el tiempo de espera ( t ) ch : = hacer ( cadena chan ) ir a leer palabra ( ch ) seleccione { palabra caso := <- ch : fmt . Println ( "Recibido" , palabra ) caso < -t : fmt . Println ( "Tiempo de espera." ) } }
El paquete de prueba brinda soporte para pruebas automatizadas de paquetes go. [130] Ejemplo de función objetivo:
func Extraer nombre de usuario ( cadena de correo electrónico ) cadena { en : = cadenas . Índice ( correo electrónico , "@" ) devolver correo electrónico [: en ] }
Código de prueba (tenga en cuenta que falta la palabra clave afirmar en Go; las pruebas se encuentran en <nombre de archivo>_test.go en el mismo paquete):
importar ( "prueba" ) func TestExtractUsername ( t * testing . T ) { t . Run ( " withoutDot " , func ( t * testing . T ) { nombre de usuario := ExtractUsername ( "[email protected]" ) if nombre de usuario != "r" { t . Fatalf ( "Got: %v\n" , nombre de usuario ) } }) t . Run ( "withDot" , func ( t * testing . T ) { nombre de usuario := ExtractUsername ( "[email protected]" ) if nombre de usuario ! = "jonh.smith" { t . Fatalf ( "Obtuve: %v\ n" , nombre de usuario ) } }) }
Es posible ejecutar pruebas en paralelo.
El paquete net/http proporciona soporte para la creación de aplicaciones web.
Este ejemplo mostraría "¡Hola mundo!" cuando se visita localhost:8080.
paquete principal importar ( "fmt" "log" "net/http" ) func holaFunc ( w http . ResponseWriter , r * http . Request ) { fmt . Fprintf ( w , "¡Hola mundo!" ) } func principal () { http . Registro de HandleFunc ( "/" , helloFunc ) . Fatal ( http . ListenAndServe ( ":8080" , nil )) }
Go ha encontrado una adopción generalizada en varios dominios debido a su sólida biblioteca estándar y su facilidad de uso. [131]
Las aplicaciones populares incluyen: Caddy , un servidor web que automatiza el proceso de configuración de HTTPS, [132] Docker , que proporciona una plataforma para la contenedorización, con el objetivo de aliviar las complejidades del desarrollo y la implementación de software, [133] Kubernetes , que automatiza la implementación. , escalamiento y administración de aplicaciones en contenedores, [134] CockroachDB , una base de datos SQL distribuida diseñada para brindar escalabilidad y consistencia sólida, [135] y Hugo , un generador de sitios estáticos que prioriza la velocidad y la flexibilidad, lo que permite a los desarrolladores crear sitios web de manera eficiente. [136]
Para obtener más ejemplos, consulte también la consulta relacionada con Wikidata.
El sistema de interfaz y la omisión deliberada de la herencia fueron elogiados por Michele Simionato, quien comparó estas características con las de Standard ML , calificando de "una pena que ningún lenguaje popular haya seguido [esta] ruta particular". [137]
Dave Astels de Engine Yard escribió en 2009: [138]
Es extremadamente fácil sumergirse en Go. Hay una cantidad mínima de conceptos fundamentales del lenguaje y la sintaxis es limpia y está diseñada para ser clara e inequívoca. Go todavía es experimental y todavía un poco tosco.
Go fue nombrado Lenguaje de Programación del Año por el Índice de la Comunidad de Programación TIOBE en su primer año, 2009, por tener un mayor aumento en popularidad en 12 meses (en sólo 2 meses, después de su introducción en noviembre) que cualquier otro lenguaje ese año. y alcanzó el puesto 13 en enero de 2010, [139] superando a lenguajes establecidos como Pascal . En junio de 2015, su clasificación había caído por debajo del puesto 50 en el índice, colocándolo por debajo de COBOL y Fortran . [140] Pero en enero de 2017, su clasificación había subido al puesto 13, lo que indica un crecimiento significativo en popularidad y adopción. Go recibió nuevamente el premio TIOBE como Lenguaje de programación del año en 2016. [ cita necesaria ]
Bruce Eckel ha declarado: [141]
La complejidad de C++ (se ha añadido aún más complejidad en el nuevo C++) y el impacto resultante en la productividad ya no se justifican. Todos los obstáculos que el programador de C++ tuvo que superar para poder utilizar un lenguaje compatible con C ya no tienen sentido: son sólo una pérdida de tiempo y esfuerzo. Go tiene mucho más sentido para la clase de problemas que C++ originalmente pretendía resolver.
Una evaluación de 2011 del lenguaje y su implementación de gc en comparación con C++ ( GCC ), Java y Scala realizada por un ingeniero de Google encontró:
Go ofrece características lingüísticas interesantes, que también permiten una notación concisa y estandarizada. Los compiladores de este lenguaje aún son inmaduros, lo que se refleja tanto en el rendimiento como en los tamaños binarios.
— R. Hundt [142]
La evaluación obtuvo una refutación por parte del equipo de desarrollo de Go. Ian Lance Taylor, que había mejorado el código Go para el artículo de Hundt, no estaba al tanto de la intención de publicar su código y dice que su versión "nunca tuvo la intención de ser un ejemplo de Go idiomático o eficiente"; Luego, Russ Cox optimizó el código Go, así como el código C++, y consiguió que el código Go se ejecutara casi tan rápido como la versión C++ y más de un orden de magnitud más rápido que el código del artículo. [143]
El 10 de noviembre de 2009, día del lanzamiento general del lenguaje, Francis McCabe, desarrollador de Go! lenguaje de programación (nótese el signo de exclamación), solicitó un cambio de nombre del lenguaje de Google para evitar confusiones con su lenguaje, que había pasado 10 años desarrollando. [150] McCabe expresó su preocupación de que "el 'tipo grande' terminará aplastándolo", y esta preocupación resonó en los más de 120 desarrolladores que comentaron en el hilo de problemas oficiales de Google diciendo que deberían cambiar el nombre, con algunos [ 151] incluso diciendo que el tema contradice el lema de Google de: No seas malvado . [152]
El 12 de octubre de 2010, el desarrollador de Google Russ Cox (@rsc) cerró el ticket de emisión pública presentado con el estado personalizado "Desafortunado" acompañado del siguiente comentario:
"Hay muchos productos y servicios informáticos llamados Go. En los 11 meses transcurridos desde nuestro lanzamiento, ha habido una confusión mínima entre los dos idiomas". [152]
Go admite funciones de primera clase, funciones de orden superior, tipos de funciones definidas por el usuario, literales de funciones, cierres y múltiples valores de retorno. Este rico conjunto de funciones admite un estilo de programación funcional en un lenguaje fuertemente tipado.
Aunque Go tiene tipos y métodos y permite un estilo de programación orientado a objetos, no existe una jerarquía de tipos.
Go está orientado a objetos, pero no de la forma habitual.
Go tiene tipificación estructural, no tipificación pato.
Se comprueba y exige la satisfacción total de la interfaz.
El idioma se llama Go.
El compilador y el tiempo de ejecución ahora están implementados en Go y ensamblador, sin C.
Ada, Go y Objective-C++ no son lenguajes predeterminados
Google ha lanzado la versión 1 de su lenguaje de programación Go, un ambicioso intento de mejorar a los gigantes del mundo de la programación de bajo nivel como C y C++.
En Go, la regla sobre la visibilidad de la información es simple: si un nombre (de un tipo de nivel superior, función, método, constante o variable, o de un campo o método de estructura) está en mayúscula, los usuarios del paquete pueden verlo.
De lo contrario, el nombre y, por tanto, el objeto que se nombra sólo es visible dentro del paquete en el que se declara.
Los paquetes de la biblioteca estándar reciben rutas de importación cortas como "fmt" y "net/http".
Para sus propios paquetes, debe elegir una ruta base que sea poco probable que entre en conflicto con futuras adiciones a la biblioteca estándar u otras bibliotecas externas.
Si guarda su código en un repositorio de origen en algún lugar, entonces debe usar la raíz de ese repositorio de origen como ruta base.
Por ejemplo, si tiene una cuenta de ejemplo en ejemplo.com/usuario, esa debería ser su ruta base.
Las ventajas de un formato único, programáticamente obligatorio para todos los programas Go superan con creces cualquier desventaja percibida del estilo particular.
Por ejemplo, alrededor del 58% de los errores de bloqueo se deben al paso de mensajes.
Además de la violación de las reglas de uso del canal de Go (por ejemplo, esperar en un canal al que nadie envía datos o al que nadie cierra), muchos errores de concurrencia son causados por el uso mixto del paso de mensajes y otras nuevas semánticas y nuevas bibliotecas en Go, que puede pasarse por alto fácilmente pero es difícil de detectar