Important Cette traduction est en cours d'élaboration. Il ne s'agit pas de la version défintive ; elle peut donc comporter des erreurs.
Ce document est une traduction en français des spécifications du langage Go – Version du 13 novembre 2013.
Ce document est un manuel de référence pour le langage de programmation Go. Pour plus d'informations et d'autres documents, voir http://golang.org.
Go est un langage à usage général conçu en ayant à l'esprit la programmation système. Il est fortement typé et possède un ramasse-miettes. Il supporte explicitement la programmation concurrente. Les programmes sont construits à partir de paquets, dont les caractéristiques permettent une gestion efficace des dépendances. Les implémentations existantes utilisent un modèle de compilation / liaison traditionnelle pour générer les binaires exécutables.
La grammaire est compacte et régulière, ce qui permet de faciliter l'analyse par des outils automatiques tels que les environnements de développement intégrés.
La syntaxe est spécifiée en utilisant la forme étendue de Backus-Naur (EBNF) :
Production = production_name "=" [ Expression ] "." . Expression = Alternative { "|" Alternative } . Alternative = Term { Term } . Term = production_name | token [ "…" token ] | Group | Option | Repetition . Group = "(" Expression ")" . Option = "[" Expression "]" . Repetition = "{" Expression "}" .
Les « Productions » sont des expressions construites à partir de termes et des opérateurs suivants, dans l'ordre de priorité croissante :
| alternation () grouping [] option (0 or 1 times) {} repetition (0 to n times)
Les noms de production minuscules sont utilisés pour identifier les jetons lexicaux. Les jetons non terminaux sont en CamelCase. Les jetons lexicaux sont entre guillemets "" ou entre accents graves `` (NDT: back quotes en anglais).
La forme a … b représente l'ensemble des caractères de a à b comme des alternatives. Les points de suspension horizontaux … sont également utilisés ailleurs dans la spécification informelle pour désigner différentes énumérations ou des extraits de code qui ne sont pas encore spécifiés. Le caractère … (par opposition aux trois caractères ...) n'est pas un jeton du langage Go.
Le code source est du texte Unicode codé en UTF-8. Le texte n'est pas canonisé, donc un seul point de code accentué est distinct du même caractère construit à partir de la combinaison d'un accent et d'une lettre ; ceux-ci sont traités comme deux points de code. Par souci de simplicité, ce document utilisera sans réserve le terme caractère pour se référer à un point de code Unicode dans le texte source.
Chaque point de code est distinct; par exemple, des lettres majuscules et minuscules sont des caractères différents.
Restriction d'implémentation : Pour la compatibilité avec d'autres outils, un compilateur peut refuser le caractère NUL (U+0000) dans le texte source.
Restriction d'implémentation : Pour assurer la compatibilité avec d'autres outils, un compilateur peut ignorer le BOM (NDT : byte order mark) UTF-8 codé (U+FEFF) si c'est le premier point de code Unicode dans le texte source. Le BOM peut être refusé partout ailleurs dans le code source.
Les termes suivants sont utilisés pour désigner des catégories spécifiques de caractères Unicode :
newline = /* Point de code Unicode U+000A */ . unicode_char = /* un point de code Unicode arbitraire sauf newline */ . unicode_letter = /* un point de code Unicode classé comme « Lettre » */ . unicode_digit = /* un point de code Unicode classé comme « chiffre décimal » */ .
Dans The Unicode Standard 6.2 et la section 4.5 "General Category", il est définit un ensemble de catégories de caractères. Go traite ces caractères dans la catégorie Lu, Ll, Lt, Lm, ou Lo comme des lettres Unicode, et ceux de la catégorie Nd comme des chiffres Unicode.
Le caractère underscore_ (U+005F) est considéré comme une lettre.
letter = unicode_letter | "_" . decimal_digit = "0" … "9" . octal_digit = "0" … "7" . hex_digit = "0" … "9" | "A" … "F" | "a" … "f" .
Il existe deux formes de commentaire :
Les commentaires ne s'imbriquent pas.
Les jetons forment le vocabulaire du langage Go. Il existe quatre catégories: les identificateurs, les mots-clés, les opérateurs et délimiteurs et les littéraux. Les espaces, formés à partir du caractère espace (U+0020), les tabulations horizontales (U+0009), les retours chariot (U+000D) et les sauts de ligne (U+000A) sont ignorés sauf ceux qui séparent les jetons qui seraient autrement combinés en un seul jeton. En outre, une nouvelle ligne ou la fin du fichier peuvent déclencher l'insertion d'un point-virgule. Durant le découpage de l'entrée en jetons, le jeton suivant est la plus longue séquence de caractères qui forme un jeton valide.
La grammaire formelle utilise des points-virgules « ; » comme terminateurs dans un certain nombre de productions. Les programmes Go peuvent omettre la plupart de ces points-virgules en utilisant les deux règles suivantes :
Lorsque l'entrée est découpée en jetons, un point-virgule est automatiquement inséré dans le flux de jetons à la fin d'une ligne non vide si le jeton final de la ligne est :
Pour tenir compte de cette bonne pratique du langage, les exemples de code de ce document ignorent les points-virgules en utilisant ces règles.
Les identificateurs nomment les entités de programme tels que les variables et les types. Un identificateur est une séquence d'une ou plusieurs lettres et chiffres. Le premier caractère d'un identificateur doit être une lettre.
identifier = letter { letter | unicode_digit } .
a _x9 ThisVariableIsExported aß
Certains identificateurs sont predeclarés.
Les mots-clés suivants sont réservés et ne peuvent pas être utilisés comme identificateurs.
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
Les séquences de caractères suivantes représentent les opérateurs, séparateurs et autres jetons spéciaux :
+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=
Un entier littéral est une séquence de chiffres représentant une constante entière. Un préfixe facultatif établit une base non décimale: 0 pour octale, 0x ou 0X pour hexadécimal. Dans les littéraux hexadécimaux, les lettres a-f et A-F représentent des valeurs allant de 10 à 15.
int_lit = decimal_lit | octal_lit | hex_lit . decimal_lit = ( "1" … "9" ) { decimal_digit } . octal_lit = "0" { octal_digit } . hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .
42 0600 0xBadFace 170141183460469231731687303715884105727
Un nombre à virgule flottante littéral est une représentation décimale d'une constante ayant une virgule flottante. Il dispose d'une partie entière, d'un point séparant les deux parties, d'une partie décimale, et d'un exposant. La partie partie entière et décimale comprennent des chiffres décimaux ; la partie exposant est un e ou E suivie d'un exposant décimal éventuellement signé. La partie entière ou la partie décimale peut être élidée, la partie décimale ou l'exposant peut être élidé.
float_lit = decimals "." [ decimals ] [ exponent ] | decimals exponent | "." decimals [ exponent ] . decimals = decimal_digit { decimal_digit } . exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
0. 72.40 072.40 // == 72.40 2.71828 1.e+0 6.67428e-11 1E6 .25 .12345E+5
Un nombre imaginaire littéral est une représentation décimale de la partie imaginaire d'un nombre complexe. Il se compose d'un nombre littéral à virgule flottant ou d'un entier naturel suivi de la lettre minuscule i.
imaginary_lit = (decimals | float_lit) "i" .
0i 011i // == 11i 0.i 2.71828i 1.e+0i 6.67428e-11i 1E6i .25i .12345E+5i
Un littéral de type rune représente une constante de type rune, un nombre entier identifiant un point de code Unicode. Un littéral de type rune est exprimé en un ou plusieurs caractères entre apostrophes. Entre les apostrophes, n'importe quel caractère peut apparaître à l'exception de l'apostrophe et du caractère de retour à la ligne. Un caractère unique entre apostrophes représente la valeur Unicode du caractère lui-même, tandis que les séquences de plusieurs caractères commençant par backslash encodent des valeurs dans différents formats.
La forme la plus simple représente le caractère unique entre apostrophes; étant donné que les fichiers sources Go sont des caractères Unicode encodés en UTF-8, plusieurs octets encodés en UTF-8 peuvent représenter une valeur entière unique. Par exemple, le littéral 'a' contient un seul octet représentant un littéral a – Unicode U+0061 – dont la valeur est 0x61, tandis que 'ä' contient deux octets (0xc30xa4) représentant le littéral a-tréma – Unicode U+00E4 – dont la valeur est0xe4.
Plusieurs échappements (à l'aide du caractère backslash) permettent de coder sous forme de texte ASCII des valeurs arbitraires. Il y a quatre façons de représenter la valeur entière comme une constante numérique: \x suivi par exactement deux chiffres hexadécimaux; \u suivi par exactement quatre chiffres hexadécimaux; \U suivie exactement huit chiffres hexadécimaux, et un caractère backslash\ suivi par exactement trois chiffres octaux. Dans chaque cas, la valeur du littéral est la valeur représentée par les chiffres dans la base correspondante.
Bien que ces représentations traduisent toutes un entier, ils ont différents intervalles de validité. Les échappements d'un nombre octal doivent représenter une valeur comprise entre 0 et 255 inclus. Les échappements d'un nombre hexadécimal remplissent cette condition par construction. Les échappements \u et \U représentent des points de code Unicode, mais certaines valeurs sont illégales, en particulier celles au-dessus 0x10FFFF et les demi-codets (NDT : en anglais surrogate halves : ces points de code allant de U+D800 à U+DFFF sont interdits – leur valeur scalaire étant réservée pour la représentation UTF-16 des points de code supplémentaires avec des paires de demi-codets).
Après un backslash, certaines échappements à caractère unique représentent des valeurs spéciales :
\a U+0007 alerte ou bip sonore \b U+0008 retour arrière \f U+000C saut de page (form feed) \n U+000A saut de ligne (line feed) \r U+000D retour chariot \t U+0009 tabulation horizontale \v U+000b tabulation verticale \\ U+005c barre oblique inverse (backslash) \' U+0027 apostrophe (échappement valide seulement dans un littéral de type rune) \" U+0022 guillemet (échappement valide seulement dans un littéral de type chaîne de caractères)
Toutes les autres séquences commençant par un backslash sont illégales à l'intérieur des littéraux de type rune.
rune_lit = "'" ( unicode_value | byte_value ) "'" . unicode_value = unicode_char | little_u_value | big_u_value | escaped_char . byte_value = octal_byte_value | hex_byte_value . octal_byte_value = `\` octal_digit octal_digit octal_digit . hex_byte_value = `\` "x" hex_digit hex_digit . little_u_value = `\` "u" hex_digit hex_digit hex_digit hex_digit . big_u_value = `\` "U" hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit . escaped_char = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
'a' 'ä' '?' '\t' '\000' '\007' '\377' '\x07' '\xff' '\u12e4' '\U00101234' 'aa' // illégal : trop de caractères '\xa' // illégal : trop peu de chiffres hexadecimaux '\0' // illégal : trop peu de chiffres octaux '\uDFFF' // illégal : demi-codets réservé pour l'UTF-16 '\U00110000' // illégal : point de code Unicode invalide
Une chaîne de caractères littérale représente une constante de type chaîne de caractères obtenue à partir de la concaténation d'une séquence de caractères. Il existe en deux formes : les chaînes « brutes » littérales et les chaînes interprétées littérales.
Les littéraux de type chaîne « brute » sont des séquences de caractères entre accents graves `` (NDT : back quote en anglais). Dans les ces deux accents graves, tout autre caractère est légal. La valeur d'une chaîne brute littérale est la chaîne composée des caractères non interprétés (implicitement codés en UTF-8) entre les guillemets, en particulier, les antislashs n'ont pas de signification particulière et la chaîne peut contenir des sauts de ligne. Les retours chariot à l'intérieur des littéraux de type chaîne brute sont éliminés de la valeur de chaîne brute.
Les littéraux représentant une chaîne interprétée sont des séquences de caractères entre guillemets "". Le texte entre les guillemets, qui ne peut pas contenir des sauts de ligne, constitue la valeur du littéral, les échappements introduits par le caractère backslash sont interprétés comme ils le sont dans les littéraux de type rune (sauf que \' est illégal et \" est légal), avec les mêmes restrictions. L'octal à trois chiffres (\nnn) et l'hexadécimal à deux chiffres (\xnn) – qui sont échappés – représentent des octets individuels de la chaîne résultante; tous les autres échappements représentent (éventuellement plusieurs octets) le codage UTF-8 de caractères individuels. Ainsi dans une chaîne littérale \377 et \xFF représentent un seul octet de valeur 0xFF=255, tandis que ÿ, \u00FF, \U000000FF et \xc3\xbf représentent les deux octets 0xc30xbf du codage UTF-8 du caractère U+00FF.
string_lit = raw_string_lit | interpreted_string_lit . raw_string_lit = "`" { unicode_char | newline } "`" . interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
`abc` // identique à "abc" `\n \n` // identique à "\\n\n\\n" "\n" "" "Hello, world!\n" "???" "\u65e5?\U00008a9e" "\xff\u00FF" "\uD800" // illégal : demi-codets réservé pour l'UTF-16 "\U00110000" // illégal : point de code Unicode invalide
Tous ces exemples représentent la même chaîne :
"???" // texte codé en UTF-8 `???` // texte codé en UTF-8 en tant que littéral brut "\u65e5\u672c\u8a9e" // points de code Unicode explicites "\U000065e5\U0000672c\U00008a9e" // points de code Unicode explicites "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // octets UTF-8 explicites
Si le code source représente un caractère avec deux points de code, telle qu'une forme combinant un accent et une lettre, le résultat sera une erreur s'il est placé dans un littéral de type rune (il ne s'agit pas d'un seul point de code), et il apparaîtra comme deux points de code si placé dans un littéral de type chaîne.
Il y a des constantes booléennes, des constantes de type rune, des constantes entières, des constantes à virgule flottante, des constantes complexes, et des constantes de type chaîne de caractères. Les runes, les entier, les nombres à virgule flottante, et les constantes complexes sont appelées constantes numériques.
Une valeur constante est représentée par un littéral de type rune, entier, nombre à virgule flottante, nombre imaginaire ou chaîne de caractères, un identificateur désignant une expression constante , une conversion avec un résultat qui est une constante, ou la valeur du résultat de certaines fonctions intégrées telles que unsafe.Sizeof appliqué à n'importe quelle valeur, cap ou len appliqués à certaines expressions, real et imag appliquées à une constante complexe et complex appliquée à des constantes numériques. Les valeurs booléennes sont représentées par les constantes prédéclaré true et false. L'identifiant iota désigne une constante entière.
En général, les constantes complexes sont une forme d'expression constante et sont discutées dans cette section.
Les constantes numériques représentent des valeurs de précision arbitraire et ne débordent pas.
Les constantes peuvent être typées ou non typées. Les constantes littérales, true, false, iota et certaines expressions constantes ne contenant que des opérandes constantes non typées ne sont pas typées.
On peut donner explicitement à une constante un type par une déclaration constante ou une conversion, ou implicitement lorsqu'il est utilisé dans une déclaration de variable ou une affectation ou comme opérande dans une expression. Il s'agit d'une erreur si la valeur constante ne peut pas être représentée comme une valeur du type correspondant. Par exemple, 3.0 peut avoir n'importe quel type entier ou type à virgule flottante, tandis que 2147483648.0 (égal à 1<<31) peut être être de type float32, float64, ou uint32 mais pas int32 ou string.
Il n'y a pas de constantes désignant l'infini (selon la norme IEEE-754) et les valeurs qui ne sont pas des nombres, mais les fonctions du paquet mathInf, NaN, IsInf, et IsNaN renvoient et testent ces valeurs au moment de l'exécution.
Restriction d'implémentation : Bien que les constantes numériques aient une précision arbitraire dans le langage go, un compilateur peut les mettre en œuvre en utilisant une représentation interne avec une précision limitée. Cela dit, chaque implémentation doit :
Ces exigences s'appliquent à la fois aux constantes littérales et au résultat de l'évaluation des expressions constantes.
Un type détermine l'ensemble des valeurs et des opérations spécifiques aux valeurs de ce type. Les types peuvent être nommés ou anonymes. Les types nommés sont précisés par un (éventuellement qualifié) nom de type, les types anonymes sont précisées en utilisant un littéral de type, ce qui compose un nouveau type en plus des types existants.
Type = TypeName | TypeLit | "(" Type ")" . TypeName = identifier | QualifiedIdent . TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType .
Les instances nommées des types booléens, numériques et chaînes de caractères sont prédéclarés. Les types composites — array, struct, pointer, function, interface, slice, map et chan — peuvent être construit en utilisant les littéraux de type.
Le type statique (ou simplement type) d'une variable est le type défini par sa déclaration. Les variables de type interface ont aussi un type dynamique distinct, qui est le type réel de la valeur stockée dans la variable lors de l'exécution. Le type dynamique peut varier pendant l'exécution mais il est toujours assignable avec le type statique de la variable d'interface. Pour tous les autres types (hors interface), le type dynamique est toujours le type statique.
Chaque type T a un type sous-jacent: Si T est un type prédéclaré ou un type littéral, le type sous-jacent correspondant est T lui-même. Sinon, le type sous-jacent de T est le type sous-jacent du type auquel T se réfère dans sa déclaration de type.
type T1 string type T2 T1 type T3 []T1 type T4 T3
Le type sous-jacent de string, T1, et T2 est string. Le type sous-jacent de []T1, T3, et T4 est []T1.
Un type peut avoir un ensemble de méthodes qui lui est associé (cf. § Types interface, § Déclarations des méthodes). L'ensemble de méthodes d'un type d'interface est son interface. L'ensemble de méthodes de tout autre type T se compose de toutes les méthodes avec le type récepteur T. L'ensemble de méthodes du type pointeur correspondant *T est l'ensemble de toutes les méthodes avec le récepteur *T ou T (cela dit, il contient également l' ensemble des méthodes de T). D'autres règles s'appliquent aux structures contenant des champs anonymes, comme décrit dans la section sur les types struct. Tout autre type a un ensemble de méthodes vide. Dans un ensemble de méthodes, chaque méthode doit avoir un nom de méthodeunique.
L'ensemble de méthodes d'un type détermine les interfaces que le type implémente et les méthodes qui peuvent être appelées en utilisant un récepteur de ce type.
Un type booléen représente l'ensemble des valeurs de vérité booléennes désignées par les constantes prédéclarées true et false. Le type booléen prédéclaré est bool.
Un type numérique représente des ensembles de valeurs entières ou à virgule flottante. Les types numériques prédéclarés et indépendants de l'architecture sont :
uint8 l'ensemble de tous les entiers non signés de 8 bits (0 à 255) uint16 l'ensemble de tous les entiers non signés de 16 bits (0 à 65535) uint32 l'ensemble de tous les entiers non signés de 32 bits (0 à 4294967295) uint64 l'ensemble de tous les entiers non signés de 64 bits (0 à 18446744073709551615) int8 l'ensemble de tous les entiers signés de 8 bits (-128 à 127) int16 l'ensemble de tous les entiers signés de 16 bits (-32768 à 32767) int32 l'ensemble de tous les entiers signés de 32 bits (-2147483648 à 2147483647) int64 l'ensemble de tous les entiers signés de 64 bits (-9223372036854775808 à 9223372036854775807) float32 l'ensemble de tous les nombres à virgule flottante de 32 bits (décrits par la norme IEEE-754) float64 l'ensemble de tous les nombres à virgule flottante de 64 bits (décrits par la norme IEEE-754) complex64 l'ensemble de tous les nombres complexes ayant des parties réelles et imaginaires de type float32 complex128 l'ensemble de tous les nombres complexes ayant des parties réelles et imaginaires de type float64 byte alias pour uint8 rune alias pour int32
La valeur d'un entier de n bits est large de n bits et elle est représentée à l'aide de l'arithémitique du complément à deux.
Il y a aussi un ensemble de types numériques prédéclarés avec des tailles spécifiques à l'implémentation :
uint soit 32 ou 64 bits int même taille que uint uintptr un entier non signé suffisamment grand pour stocker les bits non interprétés d'une valeur de pointeur
Pour éviter les problèmes de portabilité tous les types numériques sont distincts sauf byte, qui est un alias pour uint8, et rune, qui est un alias pour int32. Les conversions sont nécessaires lorsque différents types numériques sont mélangés dans une expression ou une affectation. Par exemple, int32 et int ne sont pas du même type, même si ils peuvent avoir la même taille sur une architecture particulière.
Un type chaîne de caractères représente l'ensemble des valeurs de chaîne de caractères. Une valeur de chaîne de caractères est une (éventuellement vide) séquence d'octets. Les chaînes sont immuables: une fois créé, il est impossible de modifier le contenu d'une chaîne. Le type chaîne de caractères prédéclaré est string.
La longueur d'une chaîne s (sa taille en octets) peut être découverte en utilisant la fonction intégrée len. La longueur est une constante calculée au moment de la compilation si la chaîne est une constante. Les octets d'une chaîne peuvent être consultés par leurs indices entiers de 0 à len(s)-1. Il est illégal de prendre l'adresse d'un tel élément, si s[i] est le ième octet d'une chaîne, &s[i] est invalide.
Un tableau est une séquence numérotée d'éléments d'un seul type, appelé le type d'élément. Le nombre d'éléments est appelé la longueur et elle n'est jamais négative.
ArrayType = "[" ArrayLength "]" ElementType . ArrayLength = Expression . ElementType = Type .
La longueur fait partie du type du tableau, elle doit évaluée avec une constante non négative et représentable par une valeur de type int. La longueur du tableau a peut être découverte en utilisant la fonction intégrée len. Les éléments peuvent être adressées par leurs indices entiers de 0 à len(a)-1. Les types tableaux sont toujours unidimensionnels mais peuvent être composés pour former des types multidimensionnels.
[32]byte [2*N] struct { x, y int32 } [1000]*float64 [3][5]int [2][2][2]float64 // identique à [2]([2]([2]float64))
Une slice (NDT : lit. « tranche ») est le descripteur d'un segment contigu d'un tableau sous-jacent et il donne accès à une séquence numérotée d'éléments de ce tableau. Un type slice est l'ensemble de toutes les tranches de tableaux de ce type d'élément. La valeur d'une tranche non initialisée est nil.
SliceType = "[" "]" ElementType .
Comme les tableaux, les slices sont indexables et ont une longueur. La longueur d'une tranche s peut être découvert par la fonction intégrée len, contrairement aux tableaux, la longueur peut changer pendant l'exécution. Les éléments peuvent être adressées par leurs indices entiers de 0 à len(s)-1. L'indice de la tranche d'un élément donné peut être inférieur à l'indice d'un même élément dans le tableau sous-jacent.
Une slice, une fois initialisé, est toujours associé à un tableau sous-jacent qui stocke ses éléments. Une slice partage donc le stockage avec son tableau et avec d'autres slices du même tableau ; par opposition, les tableaux distincts représentent toujours un stockage distinct.
Le tableau sous-jacent d'une slice peut s'étendre au-delà de la fin de la slice. La capacité est une mesure de cette étendue : elle est la somme de la longueur d'une tranche et de la longueur du tableau au-delà de cette tranche ; une slice avec une longueur allant jusqu'à être égale à cette capacité peut être créé par le slicing d'une nouvelle slice à partir de la slice initiale. La capacité d'une tranche a peut être découvert au moyen de la fonction intégrée cap(a).
Une nouvelle valeur de slice initialisée pour un type d'élément donné T est faite en utilisant la fonction intégrée make, qui prend un type de slice et des paramètres spécifiant la longueur et éventuellement la capacité. Une slice créée avec make alloue toujours un nouveau tableau caché auquel la valeur de la slice retournée se réfère. Autrement dit, l'exécution de ce code :
make([]T, length, capacity)
produit la même slice que l'allocation d'un tableau puis l'utilisation du slicing auraient produit ; donc ces deux expressions sont équivalentes :
make([]int, 50, 100) new([100]int)[0:50]
Comme les tableaux, les slices sont toujours unidimensionnelles mais peuvent être constitués pour construire des objets de dimension supérieure. Avec des tableaux de tableaux, les tableaux intérieurs ont, par construction, toujours la même longueur, mais avec des slices de slices (ou des tableaux de slices), les longueurs intérieures peuvent varier dynamiquement. En outre, les slices intérieures doivent être initialisées individuellement.
Une structure est une séquence d'éléments nommés, appelés champs, ayant chacun un nom et un type. Les noms des champs peuvent être spécifiés explicitement (IdentifierList) ou implicitement (AnonymousField). Dans une structure, les noms de champs qui n'utilisent pas l'identifiant blank doivent être uniques.
StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] . AnonymousField = [ "*" ] TypeName . Tag = string_lit .
// Une structure vide. struct {} // Une structure avec 6 champs. struct { x, y int u float32 _ float32 // remplissage (padding) avec l'identifiant blank A *[]int F func() }
Un champ déclaré avec un type, mais sans nom explicite de champ est un champ anonyme, également appelé champ intégré ou une intégration du type dans la structure. Un type intégré doit être spécifié comme un nom de type T ou comme un pointeur sur un nom de type non interface *T, et T lui-même ne peut pas être un type pointeur. Le nom du type non qualifié agit comme le nom du champ.
// Une structure avec 4 champs anonymes de type T1, *T2, P.T3 et *P.T4 struct { T1 // le nom du champ est T1 *T2 // le nom du champ est T2 P.T3 // le nom du champ est T3 *P.T4 // le nom du champ est T4 x, y int // les noms des champs sont x et y }
La déclaration suivante est illégale car les noms de champ doivent être uniques dans un type structure :
struct { T // conflit avec les champs anonymes *T et *P.T *T // conflit avec les champs anonymes T et *P.T *P.T // conflit avec les champs anonymes T et *T }
Un champ ou une méthodef d'un champ anonyme dans une structure x est appelé promu si x.f est un sélecteur légal qui désigne ce champ ou cette méthode f.
Les champs promus agissent comme les champs ordinaires d'une structure, sauf qu'ils ne peuvent pas être utilisés comme noms de champs dans les littéraux composites de la structure.
Prenons un type de structure S et un type nommé T, les méthodes promues sont inclues dans l'ensemble de méthodes de la structure comme suit :
Une déclaration de champ peut être suivie par une balise optionnelle (littéral de type chaîne de caractères), qui devient un attribut pour tous les champs de la déclaration du champ correspondant. Les balises sont visibles à travers une interface de réflexion et prennent part à l'identité de type pour les structures, mais sont ignorés pour le reste.
// Une structure correspondant au "TimeStamp protocol buffer". // Les balises définissent les numéros de champ du "protocol buffer". struct { microsec uint64 "field 1" serverIP6 uint64 "field 2" process string "field 3" }
Un type pointeur désigne l'ensemble de tous les pointeurs vers les variables d'un type donné, appelé le type de base du pointeur. La valeur d'un pointeur non initialisé est nil.
PointerType = "*" BaseType . BaseType = Type .
*Point *[4]int
Un type fonction représente l'ensemble de toutes les fonctions avec les mêmes types de paramètres et de résultats. La valeur d'une variable non initialisée de type fonction est nil.
FunctionType = "func" Signature . Signature = Parameters [ Result ] . Result = Parameters | Type . Parameters = "(" [ ParameterList [ "," ] ] ")" . ParameterList = ParameterDecl { "," ParameterDecl } . ParameterDecl = [ IdentifierList ] [ "..." ] Type .
Dans une liste de paramètres ou de résultats, les noms (identifierList) doivent être soit tous présents ou tous absents. S'ils sont présents, chaque nom représente un élément (paramètre ou résultat) du type spécifié et tous les noms n'utilisant pas l'identifiant blank de la signature doit être uniques. En cas d'absence, chaque type représente un élément de ce type. Paramètres et listes de résultats sont toujours mis entre parenthèses, sauf dans le cas où il y a exactement un seul résultat sans nom : il peut être écrit comme un type sans parenthèses.
Le dernier paramètre dans une signature de fonction peut avoir un type préfixé avec .... Une fonction avec un tel paramètre est appelée variadic et peut être invoquée avec zéro ou plusieurs arguments pour ce paramètre.
func() func(x int) int func(a, _ int, z float32) bool func(a, b int, z float32) (bool) func(prefix string, values ...int) func(a, b int, z float64, opt ...interface{}) (success bool) func(int, int, float64) (float64, *[]int) func(n int) func(p *T)
Un type d'interface spécifie un ensemble de méthodes appelé son interface. Une variable de type interface peut stocker une valeur d'un type quelconque avec un ensemble de méthodes qui est n'importe quel super-ensemble de l'interface. On dit qu'un tel type implémente l'interface. La valeur d'une variable de type interface non initialisée est nil.
InterfaceType = "interface" "{" { MethodSpec ";" } "}" . MethodSpec = MethodName Signature | InterfaceTypeName . MethodName = identifier . InterfaceTypeName = TypeName .
Comme avec tous les ensembles de méthodes, dans un type interface, chaque méthode doit avoir un nom unique.
// Une simple interface fichier interface { Read(b Buffer) bool Write(b Buffer) bool Close() }
Plus d'un type peut implémenter une interface. Par exemple, si deux types S1 et S2 ont l'ensemble de méthodes :
func (p T) Read(b Buffer) bool { return … } func (p T) Write(b Buffer) bool { return … } func (p T) Close() { … }
(où T représente soit S1 ou S2), l'interface File est implémentée par les deux types S1 et S2, indépendamment de ce que les autres méthodes S1 et S2 peuvent avoir ou partager.
Un type implémente toute interface comprenant une partie quelconque de ses méthodes et peut donc implémenter plusieurs interfaces distinctes. Par exemple, tous les types implémentent l'interface vide :
interface{}
De même, considérez cette spécification d'interface, qui apparaît dans une déclaration de type pour définir une interface appelée Lock :
type Lock interface { Lock() Unlock() }
Si S1 et S2 implémentent aussi :
func (p T) Lock() { … } func (p T) Unlock() { … }
ils implémentent l'interface Lock ainsi que l'interface File.
Une interface peut utiliser un nom de type interface T au lieu d'une spécification de méthode. L'effet, appelé intégration d'une interface, est équivalent à l'énumération des méthodes de T qui sont explicitement dans l'interface.
type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type File interface { ReadWrite // identique à l'énumération des méthodes dans ReadWrite Lock // identique à l'énumération des méthodes dans Lock Close() }
Un type interface T ne peut pas s'intégrer lui-même ou n'importe quel type d'interface qui intègre T, de manière récursive.
// illégal : Bad ne peut pas s'intégrer lui-même type Bad interface { Bad } // illégal : Bad1 ne peut pas s'intégrer lui-même via Bad2 type Bad1 interface { Bad2 } type Bad2 interface { Bad1 }
Une map est un groupe non ordonné d'éléments d'un type, appelé le type d'élément, elle est indexée par un ensemble de keys uniques d'un autre type, appelé le type de clé. La valeur d'une map non initialisée est nil.
MapType = "map" "[" KeyType "]" ElementType . KeyType = Type .
Les opérateurs de comparaison== et != doit être entièrement définis pour des opérandes de type clé; Donc le type de clé ne doit pas être une fonction, une map, ou une slice. Si le type de clé est un type interface, ces opérateurs de comparaison doivent être définis pour les valeurs de clés dynamiques ; les échecs provoqueront une panique lors de l'exécution.
map[string]int map[*T]struct{ x, y float64 } map[string]interface{}
Le nombre d'éléments dans une map est appelé sa longueur. Pour une une mapm, elle peut être découvert en utilisant la fonction intégrée len et elle peut changer en cours d'exécution. Les éléments peuvent être ajoutés en cours d'exécution en utilisant une affectation et récupérés avec des expressions d'index, ils peuvent être enlevés avec la fonction intégrée delete.
Une nouvelle valeur vide de type map est créée en utilisant la fonction intégrée make, qui prend le type de map et, optionnellement, une approximation de sa capacité comme arguments :
make(map[string]int) make(map[string]int, 100)
La capacité initiale ne limite pas sa taille : les maps s'accroissent afin d'accueillir le nombre d'éléments stockés en eux, à l'exception des maps non initialisées (nil). Une map non initialisée équivaut à une map vide, sauf qu'aucun élément ne peut y être ajouté.
Un canal (NDT : chan en anglais) fournit un mécanisme de synchronisation et de communication à deux fonctions s'exécutant simultanément. Il leur permet de synchroniser leurs exécutions et de communiquer en passant une valeur d'un type d'élément spécifié. La valeur d'un canal non initialisé est nil.
ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType .
L'opérateur <- précise la direction du canal : envoyer ou recevoir. Si aucune direction n'est donnée, le canal est bidirectionnel. Un canal peut être restreint à envoyer seulement ou à recevoir seulement que par une conversion ou une affectation.
chan T // peut être utilisé pour envoyer ou recevoir des valeurs de type T chan<- float64 // peut être utilisé pour envoyer seulement des float64s <-chan int // peut être utilisé pour recevoir seulement des entiers
L'opérateur <- s'associe avec le chan le plus à gauche possible :
chan<- chan int // identique à chan<- (chan int) chan<- <-chan int // identique à chan<- (<-chan int) <-chan <-chan int // identique à <-chan (<-chan int) chan (<-chan int)
Une nouvelle valeur initialisée de type chan, peut être créée en utilisant la fonction intégrée make, qui prend le type de canal et, optionnellement, une capacité comme arguments :
make(chan int, 100)
La capacité, en nombre d'éléments, définit la taille de la mémoire tampon dans le canal. Si la capacité est supérieure à zéro, le canal est asynchrone: les opérations de communication réussissent sans bloquer tant que le tampon n'est pas plein (envoie) ou non vide (reçoit), et les éléments sont reçus dans l'ordre où ils sont envoyés. Si la capacité est égale à zéro ou absente, la communication ne réussit que si à la fois un émetteur et le récepteur sont prêts. Un canal non initialisé (nil) n'est jamais prêt pour la communication.
Un canal peut être fermé avec la fonction intégrée close, la forme d'affection à valeurs multiples de l'opérateur de réception teste si un canal a été fermé.
Deux types sont soit identiques ou différents.
Deux types nommés sont identiques si leurs noms de type proviennent de la même TypeSpec. Un type nommé et un type anonyme sont toujours différents. Deux types anonymes sont identiques si les littéraux de type correspondants sont identiques, ce qui est vrai s'ils ont la même structure littérale et si les composants correspondants ont des types identiques. Dans le détail :
Compte tenu des déclarations suivantes :
type ( T0 []string T1 []string T2 struct{ a, b int } T3 struct{ a, c int } T4 func(int, float64) *T0 T5 func(x int, y float64) *[]string )
ces types sont identiques :
T0 et T0 []int et []int struct{ a, b *T5 } et struct{ a, b *T5 } func(x int, y float64) *[]string et func(int, float64) (result *[]string)
T0 et T1 sont différents parce qu'ils sont des types nommés avec des déclarations distinctes ; func(x int, y float64) *T0 et func(x int, y float64) *[]string sont différents parce T0 est différent de []string.
Une valeur x est assignable à une variable de type T (« x est assignable à T ») dans n'importe lequel de ces cas :
Un bloc est une séquence éventuellement vide de déclarations et d'instructions entre des accolades qui se correspondent.
Block = "{" StatementList "}" . StatementList = { Statement ";" } .
En plus des blocs explicites dans le code source, il y a des blocs implicites :
Les blocs s'imbriquent et l'influencent la portée.
Une déclaration lie un identifiant (sauf l'identifiant blank) à une constante, un type, une variable, une fonction, une étiquette ou un paquet. Chaque identifiant dans un programme doit être déclaré. Aucun identifiant ne peut être déclaré deux fois dans le même bloc, et aucun identifiant ne peut être déclaré à la fois dans le fichier et le bloc d'un paquet.
L'identifiant blank peut être utilisé comme n'importe quel autre identifiant dans une déclaration, mais il n'introduit pas de liaison et donc il n'est pas déclaré.
Declaration = ConstDecl | TypeDecl | VarDecl . TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
La portée d'un identifiant déclaré est l'étendue du texte source dans lequel l'identifiant désigne la constante, le type, la variable, la fonction, l'étiquette ou le paquet spécifié.
La portée, dans le langage Go, respecte ces règles lexicales d'utilisation des blocs :
Un identifiant déclaré dans un bloc peut être redéclarée dans un bloc interne. Tant que l'identifiant de la déclaration interne est dans la portée, il désigne l'entité déclarée par la déclaration interne.
La clause de paquet n'est pas une déclaration ; le nom du paquet n'apparaît pas dans n'importe quel portée. Son but est d'identifier les fichiers appartenant au même paquet et de préciser le nom du paquet par défaut pour les déclarations d'importation.
Les étiquettes sont déclarées par les instructions étiquettées et sont utilisées par les instructions break, continue et goto. Il est interdit de définir une étiquette qui n'est jamais utilisée. Contrairement à d'autres identifiants, les étiquettes n'ont pas de portée de bloc et n'entrent pas en conflit avec les identifiants qui ne sont pas des étiquettes. La portée d'une étiquette est le corps de la fonction dans laquelle elle est déclarée et exclut le corps des éventuelles fonctions imbriquées.
L'identifiant blank est représenté par le caractère de soulignement _. Il sert comme un espace réservé anonyme au lieu d'un identifiant normal (non blank) et il a une signification spéciale dans les déclarations, en tant qu'opérande, et dans les affectations.
Les identifiants suivants sont implicitement déclarés dans le bloc univers :
Types : bool byte complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr Constantes : true false iota Valeurs zéro : nil Functions : append cap close complex copy delete imag len make new panic print println real recover
Un identifiant peut être exporté pour permettre l'accès à partir d'un autre paquet. Un identifiant est exportée à ces deux conditions :
Tous les autres identifiants ne sont pas exportés.
Si l'on considère un ensemble d'identifiants, un identifiant est appelé unique s'il est différent de tous les autres dans l'ensemble. Deux identifiants sont différents s'ils sont orthographiés différemment, ou s'ils apparaissent dans des paquets différents et ne sont pas exportés. Dans le cas contraire, ils sont les mêmes.
Une déclaration de constante lie une liste d'identifiants (les noms des constantes) aux valeurs d'une liste d'expressions constantes. Le nombre d'identifiants doit être égal au nombre d'expressions, et le nème identifiant à gauche est lié à la valeur de la nème expression à droite.
ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . IdentifierList = identifier { "," identifier } . ExpressionList = Expression { "," Expression } .
Si le type est présent, toutes les constantes prennent le type spécifié, mais les expressions doivent être assignables à ce type. Si le type est omis, les constantes prennent les types individuels des expressions correspondantes. Si les valeurs d'expression sont des constantes non typées, les constantes déclarées restent non typées et les identifiants de constantes désignent les valeurs constantes. Par exemple, si l'expression est un littéral à virgule flottante, l'identifiant de la constante désigne une constante à virgule flottante, même si la partie décimale du littéral est zéro.
const Pi float64 = 3.14159265358979323846 const zero = 0.0 // constante à virgule flottante non typée const ( size int64 = 1024 eof = -1 // constante entière non typée ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", constantes entière et chaîne non typéee const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Dans une liste – entre parenthèses – de déclaration à l'aide du mot-clé const, la liste d'expressions peut tout omettre sauf la première déclaration. Une telle liste vide est équivalente à la substitution textuelle de la première liste d'expressions non-vides précédente et de son type le cas échéant. Omettre la liste d'expressions équivaut donc à répéter la liste précédente. Le nombre d'identifiants doit être égal au nombre d'expressions dans la liste précédente. Utilisé avec le générateur de constante iota, ce mécanisme permet de déclarer facilement des valeurs séquentielles :
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // cette constante n'est pas exportée )
Dans une déclaration de constante, l'identifiant prédéclaré iota représente une succession de constantes entières non typées. Il est remis à 0 à chaque fois que le mot réservé const apparaît dans la source et il est incrémenté après chaque ConstSpec. Il peut être utilisé pour construire un ensemble de constantes associées :
const ( // iota est initialisé à 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( a = 1 << iota // a == 1 (iota a été initialisé) b = 1 << iota // b == 2 c = 1 << iota // c == 4 ) const ( u = iota * 42 // u == 0 (constante entière non typée) v float64 = iota * 42 // v == 42.0 (constante float64) w = iota * 42 // w == 84 (constante entière non typée) ) const x = iota // x == 0 (iota a été initialisé) const y = iota // y == 0 (iota a été initialisé)
Dans une ExpressionList, la valeur de chaque iota est la même car il est incrémenté après chaque ConstSpec :
const ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 bit1, mask1 // bit1 == 2, mask1 == 1 _, _ // skips iota == 2 bit3, mask3 // bit3 == 8, mask3 == 7 )
Ce dernier exemple exploite la répétition implicite de la dernière liste d'expressions non-vide.
Une déclaration de type lie un identifiant et le nom du type à un nouveau type qui a le même type sous-jacent qu'un type existant. Le nouveau type est différent du type existant.
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . TypeSpec = identifier Type .
type IntArray [16]int type ( Point struct{ x, y float64 } Polar Point ) type TreeNode struct { left, right *TreeNode value *Comparable } type Block interface { BlockSize() int Encrypt(src, dst []byte) Decrypt(src, dst []byte) }
Le type déclaré n'hérite d'aucune des méthodes liées au type existant, mais l'ensemble des méthodes d'un type interface ou des éléments d'un type composite restent inchangés :
// Un Mutex est un type de données avec deux méthodes, Lock et Unlock. type Mutex struct { /* champs du Mutex */ } func (m *Mutex) Lock() { /* implémentation de Lock */ } func (m *Mutex) Unlock() { /* implémentation de Unlock */ } // NewMutex a la même composition que Mutex mais son ensemble de méthodes est vide. type NewMutex Mutex // L'ensemble de méthodes du type de base de PtrMutex reste inchangé, // mais l'ensemble de méthodes de PtrMutex est vide. type PtrMutex *Mutex // L'ensemble de méthodes de *PrintableMutex contient les méthodes // Lock et Unlock liées à son champ anonyme Mutex. type PrintableMutex struct { Mutex } // MyBlock est un type interface qui a le même ensemble de méthodes que Block. type MyBlock Block
Une déclaration de type peut être utilisée pour définir un type de booléen, de numérique ou de chaîne de caractères différent et y attacher des méthodes :
type TimeZone int const ( EST TimeZone = -(5 + iota) CST MST PST ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT+%dh", tz) }
Une déclaration de variable crée une variable, la lie à un identifiant, lui donne un type et éventuellement une valeur initiale.
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
var i int var U, V, W float64 var k = 0 var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // recherche dans une map; nous sommes seulement intéressés par "found"
Si une liste d'expressions est donnée, les variables sont initialisées en affectant les expressions aux variables dans l'ordre; toutes les expressions doivent être consommés et toutes les variables initialisées depuis les expressions. Sinon, chaque variable est initialisée à sa valeur zéro.
Si le type est présent, on donne à chaque variable ce type. Dans le cas contraire, les types se déduisent de l'affectation de la liste d'expressions.
Si le type est absent et que l'expression correspondante est évaluée à une constante non typée, le type de la variable déclarée est tel que décrit dans le paragraphe « affectation ».
Restriction d'implémentation : Un compilateur peut rendre illégal la déclaration d'une variable à l'intérieur d'un corps de fonction si la variable n'est jamais utilisée.
La déclarations abrégées des variables utilise cette syntaxe :
ShortVarDecl = IdentifierList ":=" ExpressionList .
C'est un raccourci par rapport à la déclaration de variable normale avec des expressions d'initialisation, mais sans types :
"var" IdentifierList = ExpressionList .
i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) r, w := os.Pipe(fd) // os.Pipe() retourne deux valeurs _, y, _ := coord(p) // coord() retourne trois valeurs; seule la coordonnée y nous interésse
Contrairement aux déclarations de variables normales, une déclaration abrégée de variable peut redéclarer les variables à condition qu'elles aient été déclarées plus tôt dans le même bloc et avec le même type, et qu'au moins l'une des variables non-blank soit nouvelle. En conséquence, la redéclaration ne peut apparaître que dans une déclaration courte à variables multiples. La redéclaration n'introduit pas de nouvelle variable, elle affecte seulement une nouvelle valeur à l'originale.
field1, offset := nextField(str, 0) field2, offset := nextField(str, offset) // redéclare offset a, a := 1, 2 // illégal : double déclaration de "a" ou pas de nouvelle variable si "a" a été declarée ailleurs
Les déclarations abrégées de variables peuvent apparaître seulement à l'intérieur des fonctions. Dans certains contextes, tels que les initialisations pour les instructions if, for, ou switch, elles peuvent être utilisées pour déclarer des variables temporaires locales.
Une déclaration de fonction lie un identifiant et le nom de la fonction, à une fonction.
FunctionDecl = "func" FunctionName ( Function | Signature ) . FunctionName = identifier . Function = Signature FunctionBody . FunctionBody = Block .
Si la signature de la fonction déclare des paramètres de résultat, la liste des instructions du corps de la fonction doit se terminer par une instruction de terminaison.
func findMarker(c <-chan int) int { for i := range c { if x := <-c; isMarker(x) { return x } } // invalide : il manque l'instruction de terminaison "return". }
Une déclaration de fonction peut omettre le corps de la fonction. Cette déclaration fournit la signature d'une fonction implémentée en dehors de Go, par exemple une routine écrite en assembleur.
func min(x int, y int) int { if x < y { return x } return y } func flushICache(begin, end uintptr) // implémentation externe
Une méthode est une fonction avec un récepteur. Une déclaration de méthode lie un identifiant et le nom de la méthode à une méthode ; la déclaration associe la méthode avec le type de base du récepteur.
MethodDecl = "func" Receiver MethodName ( Function | Signature ) . Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" . BaseTypeName = identifier .
Le type de récepteur doit être de la forme T ou *T où T est un nom de type. Le type désigné par T est appelé le type de base du récepteur, il ne doit pas être un pointeur ou type interface et il doit être déclaré dans le même paquet que la méthode. La méthode est dite liée au type de base et le nom de la méthode est visible uniquement dans les sélecteurs de ce type.
Un identifiant de récepteur non blank doit être unique dans la signature de méthode. Si la valeur du récepteur n'est pas référencée dans le corps de la méthode, son identifiant peut être omis dans la déclaration. La même chose s'applique en général aux paramètres des fonctions et des méthodes.
Pour un type de base, les noms non blank de méthodes qui lui sont liées doivent être uniques. Si le type de base est un type struct, la méthode et les noms de champs non blank doivent être distincts.
Pour le type Point, les déclarations suivantes :
func (p *Point) Length() float64 { return math.Sqrt(p.x * p.x + p.y * p.y) } func (p *Point) Scale(factor float64) { p.x *= factor p.y *= factor }
lient les méthodes Length et Scale, avec le type de récepteur *Point au type de base Point.
Le type d'une méthode est le type d'une fonction avec le récepteur comme premier argument. Par exemple, la méthode Scale est de type :
func(p *Point, factor float64)
Cependant, une fonction déclarée de cette façon n'est pas une méthode.
Une expression spécifie le calcul d'une valeur en appliquant des opérateurs et des fonctions aux opérandes.
Les opérandes désignent les valeurs élémentaires dans une expression. Une opérande peut être un littéral, un (éventuellement qualifié) identifiant non blank désignant une constante, une variable, une fonction ou une expression de méthode qui produit une fonction, ou une expression entre parenthèses.
L'identifiant blank peut apparaître en tant qu'opérande uniquement sur le côté gauche d'une affectation.
Operand = Literal | OperandName | MethodExpr | "(" Expression ")" . Literal = BasicLit | CompositeLit | FunctionLit . BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . OperandName = identifier | QualifiedIdent.
Un identifiant qualifié est un identifiant préfixé par le nom de paquet. Le nom du paquet et l'identifiant ne doivent pas être l'identifiant blank.
QualifiedIdent = PackageName "." identifier .
Un identifiant qualifié accède à un identifiant dans un package différent, qui doit être importé. L'identifiant doit être exporté et déclaré dans le bloc de paquet de ce paquet.
math.Sin // désigne la fonction Sin dans le paquet math
Les littéraux composites construisent des valeurs pour des structures, des tableaux, des slices, et des map et créent une nouvelle valeur à chaque fois qu'ils sont évalués. Ils se composent du type de la valeur suivie d'une liste entre accolades d'éléments composites. Un élément peut être une expression unique ou une paire clé-valeur.
CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = Element { "," Element } . Element = [ Key ":" ] Value . Key = FieldName | ElementIndex . FieldName = identifier . ElementIndex = Expression . Value = Expression | LiteralValue .
Le LiteralType doit être de type structure, tableau, slice ou map (la grammaire impose cette contrainte, sauf lorsque le type est donné comme un TypeName). Les types des expressions doivent être assignables pour – respectivement – le champ, l'élément et les principaux types du LiteralType ; il n'y a pas de conversion supplémentaire. La clé est interprétée comme un nom de champ pour les littéraux de type struct, un indice pour les littéraux de type tableau et de slice, une clé pour les littéraux de type map. Pour les littéraux de type map, tous les éléments doivent avoir une clé. C'est une erreur de spécifier plusieurs éléments avec le même nom de champ ou une valeur de clé constante.
Pour littéraux de type struct, les règles suivantes s'appliquent:
Si l'on considère les déclarations suivantes :
type Point3D struct { x, y, z float64 } type Line struct { p, q Point3D }
On pourrait écrire :
origin := Point3D{} // valeur zéro pour Point3D line := Line{origin, Point3D{y: -4, z: 12.3}} // valeur zéro pour line.q.x
Pour des littéraux de type tableau et slice, les règles suivantes s'appliquent :
Obtenir l'adresse d'un littéral composite génère un pointeur vers une instance unique de la valeur du littéral.
var pointer *Point3D = &Point3D{y: 1000}
La longueur d'un littéral de tableau est la longueur spécifiée dans le LiteralType. Si moins d'éléments que la longueur sont fournis dans le littéral, les éléments manquants sont initialisé à la valeur zéro pour le type d'élément du tableau. Il s'agit d'une erreur que de fournir des éléments avec des valeurs d'index en dehors de la plage d'index du tableau. La notation ... spécifie une longueur de tableau égale à l'indice de l'élément maximum plus un.
buffer := [10]string{} // len(buffer) == 10 intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6 days := [...]string{"Sat", "Sun"} // len(days) == 2
Un littéral de type slice décrit l'ensemble du tableau littéral sous-jacent. Ainsi, la longueur et la capacité d'un littéral de type slice sont l'indice de l'élément maximal plus un. Un littéral de type slice a la forme suivante :
[]T{x1, x2, … xn}
c'est un raccourci pour une opération de coupe appliquée à un tableau :
tmp := [n]T{x1, x2, … xn} tmp[0 : n]
Dans un littéral composite de type tableau, slice ou le type de mapT, les éléments qui sont eux-mêmes des littéraux composites peuvent élider le type de littéral respectif s'il est identique au type de T de l'élément. De même, les éléments qui sont des adresses de littéraux composites peuvent élider la référence au type &T lorsque le type d'élément est *T.
[...]Point{{1.5, -3.5}, {0, 0}} // identique à [...]Point{Point{1.5, -3.5}, Point{0, 0}} [][]int{{1, 2, 3}, {4, 5}} // identique à [][]int{[]int{1, 2, 3}, []int{4, 5}} [...]*Point{{1.5, -3.5}, {0, 0}} // identique à [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
Une ambiguïté d'analyse se pose quand un composite littéral utilisant la forme TypeName du LiteralType apparaît entre le mot-clé et l'accolade d'ouverture du bloc d'une instruction if, for ou switch, parce que les accolades entourant les expressions dans le littéral sont confondus avec ceux qui introduisent le bloc d'instructions. Pour résoudre l'ambiguïté dans ce cas rare, le littéral composite doit figurer entre parenthèses.
if x == (T{a,b,c}[i]) { … } if (x == T{a,b,c}[i]) { … }
Exemples de littéraux array, slice et map valides :
// liste de nombres premiers primes := []int{2, 3, 5, 7, 9, 2147483647} // vowels[ch] est vrai si ch est une voyelle vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true} // Pour un array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1} // fréquences en Hz pour la gamme tempérée (A4 = 440Hz) noteFrequency := map[string]float32{ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83, "G0": 24.50, "A0": 27.50, "B0": 30.87, }
Un littéral de fonction représente une fonction anonyme.
FunctionLit = "func" Function .
func(a, b int, z float64) bool { return a*b < int(z) }
Un littéral de fonction peut être affecté à une variable ou invoqué directement.
f := func(x, y int) int { return x + y } func(ch chan int) { ch <- ACK }(replyChan)
Les littéraux de fonction sont des closures : ils peuvent se référer à des variables définies dans une fonction environnante. Ces variables sont ensuite partagées entre la fonction environnante et la fonction littérale, et elles survivent aussi longtemps qu'elles sont accessibles.
Les expressions primaires sont les opérandes des expressions unaires et binaires.
PrimaryExpr = Operand | Conversion | BuiltinCall | PrimaryExpr Selector | PrimaryExpr Index | PrimaryExpr Slice | PrimaryExpr TypeAssertion | PrimaryExpr Call . Selector = "." identifier . Index = "[" Expression "]" . Slice = "[" ( [ Expression ] ":" [ Expression ] ) | ( [ Expression ] ":" Expression ":" Expression ) "]" . TypeAssertion = "." "(" Type ")" . Call = "(" [ ArgumentList [ "," ] ] ")" . ArgumentList = ExpressionList [ "..." ] .
x 2 (s + ".txt") f(3.1415, true) Point{1, 2} m["foo"] s[i : j + 1] obj.color f.p[i].x()
Pour une expression primairex qui n'est pas un nom de paquet, l'expression de sélection :
x.f
désigne le champ ou une méthode f de la valeur x (ou parfois *x ; voir ci-dessous). L'identifiant f est appelé le sélecteur (de champ ou de méthode), il ne doit pas être l'identifiant blank. Le type de l'expression de sélection est le type de f. Si x est un nom de paquet, voir la section concernant les identifiants qualifiés.
Un sélecteur f peut désigner un champ ou une méthode f d'un type T ou il peut se référer à un champ ou une méthode f d'un champ anonyme imbriqué de T. Le nombre de champs anonymes traversés pour atteindre f est appelé sa profondeur dans T. La profondeur d'un champ ou d'une méthode f déclaré dans T est zéro. La profondeur d'un champ ou d'une méthode f a déclaré dans un champ anonyme A dans T est la profondeur de f dans A plus un.
Les règles suivantes s'appliquent aux sélecteurs :
Les sélecteurs déréférencent automatiquement les pointeurs sur structures. Si x est un pointeur vers une structure, x.y est un raccourci pour (*x).y;. Si le champ y est aussi un pointeur vers une structure, x.y.z est un raccourci pour (*(*x).y).z, et ainsi de suite. Si x contient un champ anonyme de type *A où A est également un type de structure, x.f est un raccourci pour (*x.A).f.
Par exemple, considérons les déclarations suivantes :
type T0 struct { x int } func (recv *T0) M0() type T1 struct { y int } func (recv T1) M1() type T2 struct { z int T1 *T0 } func (recv *T2) M2() var p *T2 // avec p != nil et p.T0 != nil
On pourrait écrire :
p.z // (*p).z p.y // ((*p).T1).y p.x // (*(*p).T0).x p.M2() // (*p).M2() p.M1() // ((*p).T1).M1() p.M0() // ((*p).T0).M0()
Une expression primaire de la forme :
a[x]
désigne l'élément du tableau, le pointeur sur un tableau, la slice, la chaîne ou la mapa indexé par x. La valeur x est appelée respectivement l'index ou la clé de map. Les règles suivantes s'appliquent :
Si a n'est pas une map :
Pour a de type arrayA :
Pour a, un pointeur vers un type array :
Pour a de type sliceS :
Pour a de type chaîne :
Pour a de type mapM :
Sinon, a[x] est illégal.
Une expression d'index sur une mapa de type map[K]V peut être utilisée dans une affectation ou une initialisation de la forme spéciale :
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
où le résultat de l'expression d'index est une paire de valeurs avec les types (V, bool). Dans cette forme, la valeur de ok est true si la clé x est présente dans la map, et false dans les cas contraires. La valeur de v est la valeur a[x] comme avec la forme à résultat unique.
Tenter d'affecter un élément d'une map égale à nil provoque une panique d'exécution.
Les expressions slice construisent une sous-chaîne ou une tranche de chaîne à partir d'une chaîne, d'un tableau, d'un pointeur sur un tableau, ou d'un slice. Il existe deux variantes : une forme simple qui spécifie une limite basse et haute et une forme complète qui spécifie également une limite sur la capacité.
Pour une chaîne, un tableau, un pointeur sur un tableau, ou un slicea, l'expression primaire :
a[low : high]
construit une sous-chaîne ou une tranche. Les indiceslow et high sélectionnent les éléments de l'opérande a qui apparaissent dans le résultat. Le résultat a des indices à partir de 0 et de longueur égale à high - low. Après le découpage du tableau a :
a := [5]int{1, 2, 3, 4, 5} s := a[1:4]
La slices a le type []int, une longueur de 3, une capacité de 4, et les éléments :
s[0] == 2 s[1] == 3 s[2] == 4
Pour plus de commodité, l'un des indices peut être omis. Un indice low manquant est équivalent à zéro, un indice high manquant est équivalent à la longueur de l'opérande tranchée :
a[2:] // identique à a[2 : len(a)] a[:3] // identique à a[0 : 3] a[:] // identique à a[0 : len(a)]
Si a est un pointeur sur un tableau, a[low : high] est un raccourci pour (*a)[low : high].
Pour les tableaux ou les chaînes, les indices sont dans les limites si 0 <= low <= high <= len(a), sinon ils sont hors limites. Pour les slices, la limite supérieure d'index est la capacité de la tranche cap(a) plutôt que la longueur. Une constante index doit être non négative et représentable par une valeur de type int. Si les deux indices sont constants, ils doivent satisfaire low <= high. Si les indices sont hors limites au moment de l'exécution, une panique d'exécution se produit.
À l'exception des chaînes non typées, si l'opérande découpée est une chaîne ou une slice, le résultat de l'opération de découpe est une valeur non constante du même type que l'opérande. Pour les opérandes qui sont des chaînes de caractères non typées le résultat est une valeur non constante de type string. Si l'opérande découpée est un tableau, il doit être adressable et le résultat de l'opération de découpe est une slice avec le même type d'élément que le tableau.
Si l'opérande découpée d'une expression slice valide est une slice égale à nil, le résultat est nil tranche. Sinon, le résultat partage son tableau sous-jacent avec l'opérande.
Pour un tableau, un pointeur sur un tableau, ou une slicea (mais pas une chaîne), l'expression primaire :
a[low : high : max]
construit une slice du même type et avec la même longueur et les mêmes éléments que la simple expression slicea[low : high]. En outre, elle contrôle la capacité de la slice résultante en la fixant à max - low. Seul le premier index peut être omis ; il vaut 0 par défaut. Après avoir découpé le tableau a :
a := [5]int{1, 2, 3, 4, 5} t := a[1:3:5]
La slicet a le type []int, la longueur 2, la capacité 4, et les éléments :
t[0] == 2 t[1] == 3
En ce qui concerne les expressions slice simples, si a est un pointeur vers un tableau, a[low : high : max] est un raccourci pour (*a)[low : high : max]. Si l'opérande découpée est un tableau, il doit être adressable.
Les indices sont dans les limites si 0 <= low <= high <= max <= cap(a), dans les autres cas, ils sont sont hors limites. Une constante/a> index ne doit pas être négative et elle doit être représentable par une valeur de type int. Si plusieurs indices sont constants, les constantes qui sont présentes doivent être dans les limites relatives les unes des autres. Si les indices sont hors limites au moment de l'exécution, une panique d'exécution se produit.
Pour une expression x de type interface et un type T, l'expression primaire :
x.(T)
vérifie que x n'est pas égal à nil et que la valeur stockée dans x est de type T. La notation x.(T) est appelée une assertion de type.
Plus précisément, si T n'est pas un type interface, x.(T) vérifie que le type dynamique de x est identique au type T. Dans ce cas, T doit implémenter le type (interface) de x ; autrement l'assertion de type est invalide parce qu'il n'est pas possible pour x de stocker une valeur de type T. Si T est un type interface, x.(T) vérifie que le type dynamique de x implémente l'interface T.
Si l'assertion de type réussit, la valeur de l'expression est la value stockée dans x et son type est T. Si l'assertion de type est fausse, une panique d'exécution se produit. En d'autres termes, même si le type dynamique de x n'est connu qu'au moment de l'exécution, le type de x.(T) est connu comme étant T dans un programme correct.
var x interface{} = 7 // x a un type dynamique int et la valeur 7 i := x.(int) // i a un type int et la valeur 7 type I interface { m() } var y I s := y.(string) // illégal: le type string n'implémente pas I (il manque la méthode m) r := y.(io.Reader) // r a pour type io.Reader et y doit implémenter à la fois I et io.Reader
Si une assertion de type est utilisée dans une affectation ou une initialisation de cette forme :
v, ok = x.(T) v, ok := x.(T) var v, ok = x.(T)
Le résultat de l'assertion est une paire de valeurs avec les types (T, bool). Si l'assertion réussit, l'expression retourne la paire (x.(T), true) ; autrement, l'expression retourne (Z, false) où Z est la valeur zéro du type T. Aucune panique d'exécution ne se produit dans ce cas. L'assertion de type dans cette construction agit donc comme un appel de fonction retournant une valeur et un booléen indicateur de succès.
Considérons l'expression f de type fonction F :
f(a1, a2, … an)
Cette expression appelle f avec les arguments a1, a2, … an. À l'exception d'un cas particulier, les arguments doivent être des expressions à valeur unique assignables aux types de paramètre de F et ils sont évalués avant que la fonction ne soit appellée. Le type de l'expression et le type du résultat de F. Une invocation de méthode est similaire, mais la méthode elle-même est spécifiée en tant que sélecteur sur une valeur du type récepteur pour cette méthode.
math.Atan2(x, y) // appel à une fonction var pt *Point pt.Scale(3.5) // appel à une méthode avec le récepteur pt
Lors d'un appel à une fonction, la valeur de fonction et les arguments sont évalués dans l'ordre habituel. Après avoir été évalués, les paramètres de l'appel sont passés par valeur à la fonction et la fonction invoquée commence son exécution. Les paramètres de retour de la fonction sont passés par valeur en retour à la fonction appelante lorsque la fonction se termine.
Appeler une fonction ayant une valeur égale à nil provoque une panique d'exécution.
Il existe un cas particulier, si les valeurs de retour d'une fonction ou d'une méthode g sont égaux en nombre et assignable individuellement aux paramètres d'une autre fonction ou méthode f, alors l'appel f(g(parameters_of_g)) invoquera f après avoir lié – dans l'ordre – les valeurs de g aux paramètres de f. L'appel de f ne doit pas contenir d'autres paramètres que l'appel de g et g doit avoir au moins une valeur de retour. Si f a un paramètre final ..., il est affecté avec les valeurs de retour de g qui restent après l'affectation des paramètres normaux.
func Split(s string, pos int) (string, string) { return s[0:pos], s[pos:] } func Join(s, t string) string { return s + t } if Join(Split(value, len(value)/2)) != value { log.Panic("test fails") }
Un appel de méthode x.m() est valide si l'ensemble de méthodes de (le type de) x contient m et que la liste d'arguments peut être attribuée à la liste des paramètres de m. Si x est adressable et que l'ensemble de méthodes de x contient m, x.m() est un raccourci pour (&x).m() :
var p Point p.Scale(3.5)
Il n'existe aucun type de méthode distinct et il n'existe pas de littéraux de type méthode.
Si f est variadique avec un type de paramètre final ...T, alors au sein de la fonction l'argument est équivalent à un paramètre de type []T. À chaque appel de f, l'argument passé au dernier paramètre est une nouvelle slice de type []T dont les éléments successifs sont les arguments réels, qui doivent tous être assignables avec le type T. La longueur de la slice est donc le nombre de paramètres liés au paramètre final et peut être différente pour chaque appel.
Compte tenu de la fonction et de l'appel :
func Greeting(prefix string, who ...string) Greeting("hello:", "Joe", "Anna", "Eileen")
dans Greeting, who aura la valeur []string{"Joe", "Anna", "Eileen"}.
Si le dernier argument est assignable à un type de slice[]T, il peut être passé sans changement en tant que valeur pour un paramètre ...T si l'argument est suivi par .... Dans ce cas, aucune nouvelle slice n'est créée.
Compte tenu de la slices et de l'appel :
s := []string{"James", "Jasmine"} Greeting("goodbye:", s...)
dans Greeting, who aura la même valeur que s avec le même tableau sous-jacent.
Les opérateurs combinent des opérandes dans des expressions.
Expression = UnaryExpr | Expression binary_op UnaryExpr . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" . mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
Les comparaisons sont discutés ailleurs dans ce docuement. Pour les autres opérateurs binaires, les types d'opérandes doivent être identiques à moins que l'opération n'implique des décalages de bits ou des constantes non typées. Pour les opérations impliquant des constantes uniquement, voir la section sur les expressions constantes.
Sauf pour les opérations de décalage de bits, si l'un des opérandes est une constante non typée et que l'autre opérande ne l'est pas, la constante est convertie au type de l'autre opérande.
L'opérande de droite dans une expression de décalage de bits doit être de type entier non signé ou être une constante non typée qui peut être converti en type entier non signé. Si l'opérande de gauche d'une expression de de décalage de bits non constante est une constante non typée, le type de la constante est ce qu'il serait si l'expression de décalage de bits était remplacée par son opérande gauche seulement.
var s uint = 33 var i = 1<<s // 1 a le type int var j int32 = 1<<s // 1 a le type int32; j == 0 var k = uint64(1<<s) // 1 a le type uint64; k == 1<<33 var m int = 1.0<<s // 1.0 a le type int var n = 1.0<<s != i // 1.0 a le type int; n == false si les entiers ont 32 bits de large var o = 1<<s == 2<<s // 1 and 2 ont le type int; o == true si les entiers ont 32bits de large var p = 1<<s == 1<<33 // illégal si les entiers ont 32bits de large : 1 a le type int, mais 1<<33 fait déborder le type int var u = 1.0<<s // illégal : 1.0 a le type float64, ne peut pas être décalée var u1 = 1.0<<s != 0 // illégal : 1.0 a le type float64, ne peut pas être décalée var u2 = 1<<s != 1.0 // illégal : 1 a le type float64, ne peut pas être décalée var v float32 = 1<<s // illégal : 1 a le type float32, ne peut pas être décalée var w int64 = 1.0<<33 // 1.0<<33 est une expression constante de décalage
Les opérateurs unaires ont la plus haute priorité. Comme les opérateurs ++ et -- forment les instructions et pas les expressions, ils sont en dehors de la hiérarchie des opérateurs. En conséquence, l'instruction *p++ est la même que (*p)++. Il existe cinq niveaux de priorité des opérateurs binaires. Les opérateurs de multiplication se lient plus fortement, suivis par les opérateurs d'addition, les opérateurs de comparaison, && (ET logique), et enfin || (OU logique) :
Priorité Opérateur 5 * / % << >> & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 ||
Les opérateurs binaires ayant la même priorité s'associent de gauche à droite. Par exemple, x / y * z est le même chose que (x / y) * z.
+x 23 + 3*x[i] x <= f() ^a >> b f() || g() x == y+1 && <-chanPtr > 0
Les opérateurs arithmétiques s'appliquent aux valeurs numériques et donnent un résultat du même type que le premier opérande. Les quatre opérateurs arithmétiques standards (+, -, *, /) s'appliquent aux entiers, nombres à virgule flottante, et aux types complexes ; + s'applique également aux chaînes de caractères. Tous les autres opérateurs arithmétiques s'appliquent uniquement aux entiers.
+ somme entiers, nombres à virgule flottante, valeurs complexs, chaînes - différence entiers, nombres à virgule flottante, valeurs complexs * produit entiers, nombres à virgule flottante, valeurs complexs / quotient entiers, nombres à virgule flottante, valeurs complexs % modulo entiers & AND bit à bit entiers | OR bit à bit entiers ^ XOR bit à bit entiers &^ bit clear (AND NOT) entiers << décalage à gauche entier << entiers non signés >> décalage à droite entier >> entiers non signés
Les chaînes peuvent être concaténées en utilisant l'opérateur + ou l'opérateur d'affectation += :
s := "hi" + string(c) s += " and good bye"
L'addition de chaînes crée une nouvelle chaîne en concaténant les opérandes.
Pour deux valeurs entières x et y, le quotient entier q = x / y et le modulo r = x % y satisfont les relations suivantes :
x = q*y + r et |r| < |y|
Avec x / y tronquée vers zéro (cf. "Opération modulo").
x y x / y x % y 5 3 1 2 -5 3 -1 -2 5 -3 -1 2 -5 -3 1 -2
Il y a une exception à cette règle, si le dividende x est la valeur la plus négative pour le type entier de x, le quotient q = x / -1 est égal à x (et r = 0).
x, q int8 -128 int16 -32768 int32 -2147483648 int64 -9223372036854775808
Si le diviseur est une constante, il ne doit pas être égal à zéro. Si le diviseur est égal à zéro au moment de l'exécution, une panique d'exécution se produit. Si le dividende est non-négatif et que le diviseur est une puissance constante de 2, la division peut être remplacée par un décalage de bits vers la droite, et le calcul du reste peut être remplacée par une opération bit à bit ET :
x x / 4 x % 4 x >> 2 x & 3 11 2 3 2 3 -11 -2 -3 -3 1
Les opérateurs de décalage de bits décalent l'opérande gauche par la valeur de décalage spécifiée par l'opérande de droite. Ils mettent en œuvre des décalages arithmétiques si l'opérande de gauche est un entier signé et des décalage logiques si l'opérande de gauche est un entier non signé. Il n'y a pas de limite supérieure à la valeur de décalage. Les décalages se comportent comme si l'opérande gauche est décalés n fois par 1 pour un compteur de décalage de n. En conséquence, x << 1 est la même chose que x*2 et x >> 1 est la même chose que x/2 mais tronqué vers l'infini négatif.
Pour les opérandes entiers, les opérateurs unaires +, -, et ^ sont définis comme suit :
+x est 0 + x -x négation est 0 - x ^x complément bit à bit est m ^ x avec m = "tous les bits mis à 1" pour x non signé et m = -1 pour x signé
Pour les nombres à virgule flottante et complexes, +x est la même chose que x, tandis que -x est la négation de x. Le résultat de la division par zéro d'un nombre à virgule flottante ou complexe n'est pas spécifié au-delà de la norme IEEE-754; le fait qu'une panique d'exécution se produise ou pas est spécifique à l'implémentation.
Pour les valeurs entières non signées, les opérations +, -, *, et << sont calculés au modulo 2n, où n est la largeur de bit du type de l'entier non signé. Grosso modo, ces opérations d'entiers non signés ne prennent pas en compte les bits de poids fort en cas de débordement, et les programmes peuvent s'appuyer sur un » wrap around «.
Pour des entiers signés, les opérations +, -, *, et << peuvent légalement déborder et la valeur résultante existe et est définie de manière déterministe par la représentation entière signée, l'opération, et ses opérandes. Aucune exception n'est déclenchée à la suite d'un débordement. Un compilateur ne peut pas optimiser le code sous l'hypothèse que le débordement ne se produise pas. Par exemple, il ne peut pas supposer que x < x + 1 est toujours vrai.
Les opérateurs de comparaison comparent deux opérandes et produisent une valeur booléenne non typée.
== égal != non égal < inférieur <= inférieur or égal > supérieur >= supérieur ou égal
Dans toute comparaison, le premier opérande doit être assignable au type du second opérande, ou vice versa.
Les opérateurs d'égalité == et != s'appliquent à des opérandes qui sont comparables. Les opérateurs d'ordre <, <=, >, and >= s'appliquent à des opérandes qui sont ordonnés. Ces termes et le résultat des comparaisons sont définis comme suit :
Une comparaison de deux valeurs interface avec des types dynamiques identiques provoque une panique d'exécution si les valeurs de ce type ne sont pas comparables. Ce comportement ne s'applique pas seulement à des directes de la valeur de l'interface, mais aussi lorsque l'on compare les tableaux de valeurs interface ou des structures avec des champs de type interface.
Les valeurs slice, map et fonction ne sont pas comparables. Cependant, il existe le cas particulier d'une valeur slice, map ou fonction qui peut être comparée à l'identifiant prédéclaré nil. Les comparaison de valeurs pointeur, canal et interface avec nil sont également autorisées et elles suivent les règles générales ci-dessus.
const c = 3 < 4 // c est la constante boolénne non typée true type MyBool bool var x, y int var ( // Le résultat d'une comparaison est un booléen non typé. // Les règles habituelles de l'affectation s'appliquent. b3 = x == y // b3 est de type booléen b4 bool = x == y // b4 est de type booléen b5 MyBool = x == y // b5 est de type MyBool )
Les opérateurs logiques s'appliquent à des valeurs booléennes et donnent un résultat du même type que les opérandes. L'opérande de droite est évaluée de manière conditionnelle.
&& conditional AND p && q is "if p then q else false" || conditional OR p || q is "if p then true else q" ! NOT !p is "not p"
Pour un opérande x tt> de Type T tt>, l'opération d'adresse et x tt> génère un pointeur de type * T tt> x tt>. L'opérande doit être adressable i>, c'est soit une variable, pointeur indirect, ou opération d'indexation de tranche; ou un sélecteur de champ d'une structure opérande adressable, ou une opération d'indexation de tableau d'un réseau adressable. Comme une exception à l'exigence de capacité d'adressage, x tt> peut également être un (éventuellement entre parenthèses) littérale a> composite. Si l'évaluation de x tt> causerait une panique panique d'exécution, puis l'évaluation de et x tt> fait trop. For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal. If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.
Pour un opérande x de type pointeur * T tt>, pointeur d'indirection * x tt> désigne la valeur de type T tt> a à par x tt>. Si x tt> est nil, une tentative pour évaluer * x tt> va provoquer une panique d'exécution. For an operand x of pointer type *T, the pointer indirection *x denotes the value of type T pointed to by x. If x is nil, an attempt to evaluate *x will cause a run-time panic.
&x &a[f(2)] &Point{2, 3} *p *pf(x) var x *int = nil *x // provoque une panique d'exécution &*x // provoque une panique d'exécution
Pour un opérande ch de type canal, la valeur de l'opération de réception <-ch est la valeur reçue du canal ch. La direction du canal doit permettre les opérations de réception, et le type de l'opération de réception est le type de l'élément du canal. L'expression est bloquante jusqu'à ce qu'une valeur soit disponible. La réception depuis un canal nil bloque indéfiniment. Une opération de réception sur un canal fermé peut toujours procéder immédiatement, produisant la valeur zéro du type d'élément.
v1 := <-ch v2 = <-ch f(<-ch) <-strobe // attendre impulsion d'horloge et ignorer la valeur reçue
Une expression de réception utilisée dans une affectation ou une initialisation de la forme :
x, ok = <-ch x, ok := <-ch var x, ok = <-ch
produit un résultat supplémentaire de type bool rapportant si la communication a réussi ou pas. La valeur de ok est true si la valeur reçue est le résultat d'une opération d'envoi réussie pour le canal, ou false si elle est une valeur zéro générée parce que le canal est fermé et vide.
Si M est dans l'ensemble de méthodes de Type T, T.M est une fonction que l'on peut appeler comme une fonction normale fonction avec les mêmes arguments que M préfixés par un argument supplémentaire qui est le récepteur de la méthode.
MethodExpr = ReceiverType "." MethodName . ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
Considérons un type structure T avec deux méthodes, Mv, dont le récepteur est de type T, et Mp, dont le récepteur est de type *T.
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // valeur récepteur func (tp *T) Mp(f float32) float32 { return 1 } // pointeur récepteur var t T
L'expression :
T.Mv
produit une fonction équivalente à Mv, mais avec un récepteur explicite comme premier argument, il a la signature :
func(tv T, a int) int
Cette fonction peut être appelée normalement avec un récepteur explicite, de sorte que ces cinq invocations sont équivalentes :
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
De même, l'expression :
(*T).Mp
produit une valeur de fonction représentant Mp avec la signature :
func(tp *T, f float32) float32
Pour une méthode avec un récepteur de valeur, on peut dériver une fonction avec un récepteur explicite de pointeur, donc :
(*T).Mv
produit une valeur de fonction représentant Mv avec la signature :
func(tv *T, a int) int
Une telle fonction passe par l'intermédiaire du récepteur pour créer une valeur à transmettre comme le récepteur de la méthode sous-jacente ; la méthode ne remplace pas la valeur dont l'adresse est transmise dans l'appel de fonction.
Le dernier cas, une fonction valeur-récepteur pour une méthode pointeur-récepteur, est illégal parce que les méthodes pointeur-récepteur ne sont pas dans l'ensemble de méthodes du type de valeur.
Les valeurs de fonction dérivées de méthodes sont appelées avec la syntaxe d'appel de fonction ; le récepteur est fournit en tant que premier argument de l'appel. Ce qui donne, pour f := T.Mv, f est invoqué comme f(t, 7) et pas t.f(7). Pour construire une fonction qui lie le récepteur, utiliser un littéral fonction ou une valeur méthode.
Il est possible de dériver une valeur de fonction à partir d'une méthode d'un type interface. La fonction résultante prend un récepteur explicite de ce type interface.
Si l'expression x est de type statique T et M est dans l'l'ensemble de méthodes de type T, x.M est appelé une valeur de méthode. La valeur de méthode x.M est une valeur de fonction qui peut être appelée avec les mêmes arguments qu'un appel de méthode de x.M. L'expression x est évaluée et enregistrée lors de l'évaluation de la valeur de méthode, la copie de sauvegarde est alors utilisée comme récepteur dans tout appel, appel qui peut être exécuté plus tard.
Le type T peut être une interface ou un type non-interface.
Comme lorsque nous avons abordé les expressions méthode plus tôt, considérez l'exemple d'un type de structure T avec deux méthodes, Mv, dont le récepteur est de type T, et Mp, dont le récepteur est de type *T.
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // récepteur valeur func (tp *T) Mp(f float32) float32 { return 1 } // récepteur pointeur var t T var pt *T func makeT() T
L'expression :
t.Mv
produit une valeur de fonction de type :
func(int) int
Ces deux appels sont équivalents :
t.Mv(7) f := t.Mv; f(7)
De même, l'expression :
pt.Mp
produit une valeur de fonction de type
func(float32) float32
Comme avec les sélecteurs, une référence à une méthode non-interface avec un récepteur de valeur utilisant un pointeur déréférencera automatiquement ce pointeur : pt.Mv est équivalent à (*pt).Mv.
Comme avec la méthode demande a>, une référence à une méthode non-interface avec un récepteur de pointeur en utilisant une valeur adressable prendra automatiquement l'adresse de cette valeur: t.Mp tt> est équivalent à (& t). Mp tt>. As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
f := t.Mv; f(7) // like t.Mv(7) f := pt.Mp; f(7) // like pt.Mp(7) f := pt.Mv; f(7) // like (*pt).Mv(7) f := t.Mp; f(7) // like (&t).Mp(7) f := makeT().Mp // invalid: result of makeT() is not addressable
Bien que les exemples ci-dessus utilisent des types non-interface, il est également légal de créer une valeur de la méthode à partir d'une valeur de type d'interface. Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type.
var i interface { M(int) } = myVal f := i.M; f(7) // like i.M(7)
Les conversions sont des expressions de la forme T (x) tt> où T tt> est un type et x tt> est une expression qui peut être converti en un type T tt>. Conversions are expressions of the form T(x) where T is a type and x is an expression that can be converted to type T.
Conversion = Type "(" Expression [ "," ] ")" .
Si le type commence par la opérateur * tt> ou <- tt>, ou si le type commence par le mot-clé fonction tt> et n'a pas de liste des résultats, il doit être mise entre parenthèses si nécessaire pour éviter toute ambiguïté: If the type starts with the operator * or <-, or if the type starts with the keyword func and has no result list, it must be parenthesized when necessary to avoid ambiguity:
*Point(p) // same as *(Point(p)) (*Point)(p) // p is converted to *Point <-chan int(c) // same as <-(chan int(c)) (<-chan int)(c) // c is converted to <-chan int func()(x) // function signature func() x (func())(x) // x is converted to func() (func() int)(x) // x is converted to func() int func() int(x) // x is converted to func() int (unambiguous)
Un constante a> valeur x tt> peut être converti en type T tt> dans aucun de ces cas: A constant value x can be converted to type T in any of these cases:
Conversion d'une constante donne une constante typée comme résultat. Converting a constant yields a typed constant as result.
uint(iota) // iota value of type uint float32(2.718281828) // 2.718281828 of type float32 complex128(1) // 1.0 + 0.0i of type complex128 float32(0.49999999) // 0.5 of type float32 string('x') // "x" of type string string(0x266c) // "?" of type string MyString("foo" + "bar") // "foobar" of type MyString string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant (*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type int(1.2) // illegal: 1.2 cannot be represented as an int string(65.0) // illegal: 65.0 is not an integer constant
Une valeur non constante x tt> peut être converti en un type T tt> dans aucun de ces cas: A non-constant value x can be converted to type T in any of these cases:
Des règles spécifiques s'appliquent aux conversions (non constante) entre les types numériques ou vers et à partir d'un type de chaîne. Ces conversions peuvent changer la représentation des x tt> et encourir un coût d'exécution. Tous les autres conversions ne changent le type mais pas la représentation x tt>. Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x and incur a run-time cost. All other conversions only change the type but not the representation of x.
Il n'existe aucun mécanisme linguistique de convertir entre les pointeurs et entiers. Le paquet dangereux tt> a> implémente cette fonctionnalité dans des circonstances restreintes. There is no linguistic mechanism to convert between pointers and integers. The package unsafe implements this functionality under restricted circumstances.
Pour la conversion de valeurs numériques non constants, les règles suivantes s'appliquent: For the conversion of non-constant numeric values, the following rules apply:
Dans toutes les conversions non constants impliquant virgule flottante ou complexes valeurs, si le type de résultat ne peut pas représenter la valeur de la conversion réussit, mais la valeur du résultat dépend de l'implémentation. In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
string('a') // "a" string(-1) // "\ufffd" == "\xef\xbf\xbd" string(0xf8) // "\u00f8" == "ø" == "\xc3\xb8" type MyString string MyString(0x65e5) // "\u65e5" == "?" == "\xe6\x97\xa5"
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø" string([]byte{}) // "" string([]byte(nil)) // "" type MyBytes []byte string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "???" string([]rune{}) // "" string([]rune(nil)) // "" type MyRunes []rune string(MyRunes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "???"
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []byte("") // []byte{} MyBytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
[]rune(MyString("???")) // []rune{0x767d, 0x9d6c, 0x7fd4} []rune("") // []rune{} MyRunes("???") // []rune{0x767d, 0x9d6c, 0x7fd4}
Les expressions constantes ne peuvent contenir que constante a> opérandes et sont évalués au moment de la compilation. Constant expressions may contain only constant operands and are evaluated at compile time.
Booléen non typé, numérique, et les constantes de chaîne peuvent être utilisés comme opérandes partout où il est légal d'utiliser un opérande de booléen, numérique ou de type chaîne, respectivement. Sauf pour les opérations de changement de vitesse, si les opérandes d'une opération binaire existe différents types de constantes non typées, le fonctionnement et, pour les opérations non-booléennes, le résultat, utilisez le type qui apparaît plus tard dans cette liste: entier, rune, virgule flottante, complexe . Par exemple, une constante de nombre entier non typé, divisé par une constante complexe non typé donne une constante complexe non typée. Untyped boolean, numeric, and string constants may be used as operands wherever it is legal to use an operand of boolean, numeric, or string type, respectively. Except for shift operations, if the operands of a binary operation are different kinds of untyped constants, the operation and, for non-boolean operations, the result use the kind that appears later in this list: integer, rune, floating-point, complex. For example, an untyped integer constant divided by an untyped complex constant yields an untyped complex constant.
Une comparaison constante a> donne toujours une constante booléenne non typée. Si l'opérande gauche d'un passer expression a> est une constante typée, le résultat est une constante entière, sinon il est une constante du même type que l'opérande de gauche, qui doit être type entier a>. L'application de tous les autres opérateurs de constantes non typées résultats dans une constante typée de la même nature (c'est un booléen, entier, virgule flottante, complexe, ou constante de type chaîne). A constant comparison always yields an untyped boolean constant. If the left operand of a constant shift expression is an untyped constant, the result is an integer constant; otherwise it is a constant of the same type as the left operand, which must be of integer type. Applying all other operators to untyped constants results in an untyped constant of the same kind (that is, a boolean, integer, floating-point, complex, or string constant).
const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant) const b = 15 / 4 // b == 3 (untyped integer constant) const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant) const T float64 = 3/2 // T == 1.0 (type float64, 3/2 is integer division) const ? float64 = 3/2. // ? == 1.5 (type float64, 3/2. is float division) const d = 1 << 3.0 // d == 8 (untyped integer constant) const e = 1.0 << 3 // e == 8 (untyped integer constant) const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32) const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant) const h = "foo" > "bar" // h == true (untyped boolean constant) const j = true // j == true (untyped boolean constant) const k = 'w' + 1 // k == 'x' (untyped rune constant) const l = "hi" // l == "hi" (untyped string constant) const m = string(k) // m == "x" (type string) const S = 1 - 0.707i // (untyped complex constant) const ? = S + 2.0e-4 // (untyped complex constant) const F = iota*1i - 1/1i // (untyped complex constant)
Appliquer la fonction intégrée complexe tt> à l'entier non typé, rune, ou constantes à virgule flottante donne une constante complexe non typée. Applying the built-in function complex to untyped integer, rune, or floating-point constants yields an untyped complex constant.
const ic = complex(0, c) // ic == 3.75i (untyped complex constant) const iT = complex(0, T) // iT == 1.5i (type complex128)
Les expressions constantes sont toujours évaluées précisément, les valeurs intermédiaires et les constantes eux-mêmes peuvent exiger une précision beaucoup plus grande que soutenu par tout type prédéclaré dans la langue. Voici les déclarations juridiques: Constant expressions are always evaluated exactly; intermediate values and the constants themselves may require precision significantly larger than supported by any predeclared type in the language. The following are legal declarations:
const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant) const Four int8 = Huge >> 98 // Four == 4 (type int8)
Le diviseur d'une opération de division ou reste constante ne doit pas être zéro: The divisor of a constant division or remainder operation must not be zero:
3.14 / 0.0 // illégal: division par zéro
Les valeurs de tapés i> constantes doivent toujours être exactement représentable en tant que valeurs de type constant. Les expressions constantes suivantes sont illégales: The values of typed constants must always be accurately representable as values of the constant type. The following constant expressions are illegal:
uint(-1) // -1 cannot be represented as a uint int(3.14) // 3.14 cannot be represented as an int int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64 Four * 300 // operand 300 cannot be represented as an int8 (type of Four) Four * 100 // product 400 cannot be represented as an int8 (type of Four)
Le masque utilisé par l'opérateur unaire de bits de complément ^ tt> correspond à la règle de non-constantes: le masque est tous les 1 pour les constantes non signés et -1 pour les constantes signés et non typés. The mask used by the unary bitwise complement operator ^ matches the rule for non-constants: the mask is all 1s for unsigned constants and -1 for signed and untyped constants.
^1 // untyped integer constant, equal to -2 uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8 ^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE) int8(^1) // same as int8(-2) ^int8(1) // same as -1 ^ int8(1) = -2
Restriction de mise en œuvre: Un compilateur peut utiliser arrondi lors du calcul non typé à virgule flottante ou des expressions constantes complexes, voir la restriction de la mise en œuvre dans la section sur les constantes de href="#Constants">. Cet arrondi peut provoquer une expression constante à virgule flottante invalide dans un contexte entier, même si elle serait intégrante lorsque calculé en utilisant une précision infinie. Implementation restriction: A compiler may use rounding while computing untyped floating-point or complex constant expressions; see the implementation restriction in the section on constants. This rounding may cause a floating-point constant expression to be invalid in an integer context, even if it would be integral when calculated using infinite precision.
Lors de l'évaluation de la opérandes a> d'une expression, affectation a>, déclaration de retour a>, tous les appels de fonction, les appels de méthode, et les opérations de communication sont évaluées dans l'ordre lexical de gauche à droite. When evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
Par exemple, dans l'affectation :
y[f()], ok = g(h(), i()+x[j()], <-c), k()
les appels et les communications fonction se produisent dans l'ordre f () tt>, h () tt>, i () tt>, j () tt>, <-c tt>, g () tt>, et k () tt>. Cependant, l'ordre de ces événements par rapport à l'évaluation et à l'indexation de x tt> et l'évaluation de y tt> n'est pas spécifié. the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.
a := 1 f := func() int { a++; return a } x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified m2 := map[int]int{a: f()} // m2 may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
Opérations à virgule flottante dans une seule expression sont évalués selon l'associativité des opérateurs. Parenthèses explicites affectent l'évaluation par la substitution de l'associativité par défaut. Dans l'expression x + (y + z) tt> le plus y + z tt> est effectuée avant d'ajouter x tt>. Floating-point operations within a single expression are evaluated according to the associativity of the operators. Explicit parentheses affect the evaluation by overriding the default associativity. In the expression x + (y + z) the addition y + z is performed before adding x.
Les instructions contrôlent l'exécution.
Statement = Declaration | LabeledStmt | SimpleStmt | GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | DeferStmt . SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
Une instruction de terminaison est l'une des instructions suivantes:
Toutes les autres déclarations ne sont pas abolis. All other statements are not terminating.
Une liste a> se termine par une déclaration de terminaison si la liste n'est pas vide et sa déclaration finale se termine. A statement list ends in a terminating statement if the list is not empty and its final statement is terminating.
La déclaration vide ne fait rien. The empty statement does nothing.
EmptyStmt = .
Une déclaration marqué peut être la cible d'un goto tt>, briser tt> ou continuer tt> déclaration. A labeled statement may be the target of a goto, break or continue statement.
LabeledStmt = Label ":" Statement . Label = identifier .
Error: log.Panic("error encountered")
À l'exception des fonctions intégrées spécifiques, la fonction et la méthode appelle a> et opérations de réception a> peuvent apparaître dans le contexte de la déclaration. Ces déclarations peuvent être mis entre parenthèses. With the exception of specific built-in functions, function and method calls and receive operations can appear in statement context. Such statements may be parenthesized.
ExpressionStmt = Expression .
Les fonctions intégrées suivantes ne sont pas autorisées dans le contexte de la déclaration: The following built-in functions are not permitted in statement context:
ajouter complexe de plafonnement imag len faire de nouvelles réel unsafe.Alignof unsafe.Offsetof unsafe.Sizeof append cap complex imag len make new real unsafe.Alignof unsafe.Offsetof unsafe.Sizeof
h(x+y) f.Close() <-ch (<-ch) len("foo") // illégale si len est la fonction intégrée
Une déclaration d'envoi envoie une valeur sur un canal. L'expression des chaînes doit être de type de canal a>, la direction du canal doit permettre les opérations d'envoi, et le type de la valeur à envoyer doit être cessible a> pour le type d'élément de la chaîne. A send statement sends a value on a channel. The channel expression must be of channel type, the channel direction must permit send operations, and the type of the value to be sent must be assignable to the channel's element type.
SendStmt = Channel "<-" Expression . Channel = Expression .
À la fois le canal et la valeur d'expression sont évaluées avant le début de la communication. Blocs de communication jusqu'à l'envoi peuvent procéder. Une émission sur un canal sans mémoire tampon peut se dérouler si un récepteur est prêt. Une émission sur un canal mémoire tampon peut procéder si il ya de la place dans la mémoire tampon. Une émission sur un canal fermé produit en provoquant une panique d'exécution. Un départ sur un néant tt> blocs de canaux toujours. Both the channel and the value expression are evaluated before communication begins. Communication blocks until the send can proceed. A send on an unbuffered channel can proceed if a receiver is ready. A send on a buffered channel can proceed if there is room in the buffer. A send on a closed channel proceeds by causing a run-time panic. A send on a nil channel blocks forever.
Channels act as first-in-first-out queues. For example, if a single goroutine sends on a channel values that are received by a single goroutine, the values are received in the order sent. Channels act as first-in-first-out queues. For example, if a single goroutine sends on a channel values that are received by a single goroutine, the values are received in the order sent.
Un seul canal peut être utilisé pour envoyer et recevoir des opérations et appelle à des fonctions intégrées dans le chapeau de tt> a> et len tt> a> par un certain nombre de goroutines sans autre synchronisation. A single channel may be used for send and receive operations and calls to the built-in functions cap and len by any number of goroutines without further synchronization.
ch <- 3
Le "+ +" et "-" états augmentent ou diminuent leurs opérandes par le non typé constante a> 1 tt>. Comme une mission, l'opérande doit être adressable a> ou une expression carte d'index. The "++" and "--" statements increment or decrement their operands by the untyped constant1. As with an assignment, the operand must be addressable or a map index expression.
IncDecStmt = Expression ( "++" | "--" ) .
La suite des déclarations d'affectation de href="#Assignments"> sont sémantiquement équivalentes: The following assignment statements are semantically equivalent:
IncDec statement Assignment x++ x += 1 x-- x -= 1
Assignment = ExpressionList assign_op ExpressionList . assign_op = [ add_op | mul_op ] "=" .
Chaque opérande côté gauche doit être adressable a>, une expression carte d'index, ou (pour = tt> Missions seulement) le identifiant blanc a>. Opérandes peuvent être mis entre parenthèses. Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier. Operands may be parenthesized.
x = 1 *p = f() a[i] = 23 (k) = <-ch // same as: k = <-ch
Une opération de cession i> x tt> op i> = tt> y tt> op i> est une opération arithmétique binaire équivalent à x tt> = tt> x tt> op i> y tt> mais évalue x tt> une seule fois. L'op i> = tt> construction est un seul jeton. Dans les opérations d'affectation, les deux listes d'expressions de droite à gauche et doit contenir exactement un expression à valeur unique, et l'expression de gauche ne doivent pas être l'identificateur vide. An assignment operationxop=y where op is a binary arithmetic operation equivalent to x=xopy but evaluates x only once. The op= construct is a single token. In assignment operations, both the left- and right-hand expression lists must contain exactly one single-valued expression, and the left-hand expression must not be the blank identifier.
a[i] <<= 2 i &^= 1<<n
Une assignation de tuple attribue les différents éléments d'une opération à plusieurs valeurs à une liste de variables. Il existe deux formes. Dans la première, l'opérande de droite est une expression à plusieurs valeurs unique comme une évaluation de fonction ou canal a> ou carte a> fonctionnement ou une affirmation de type a>. Le nombre d'opérandes sur le côté gauche, doit correspondre au nombre de valeurs. Par exemple, si f tt> est une fonction qui retourne deux valeurs, A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function evaluation or channel or map operation or a type assertion. The number of operands on the left hand side must match the number of values. For instance, if f is a function returning two values,
x, y = f()
attribue la première valeur à x tt> et la seconde à y tt>. Dans la seconde forme, le nombre d'opérandes de gauche doit être égal au nombre d'expressions sur le droit, dont chacun doit être à valeur unique, et n i> e expression de droite est affectée à la n i> e opérande à gauche: assigns the first value to x and the second to y. In the second form, the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left:
one, two, three = '?', '?', '?'
The blank identifier provides a way to ignore right-hand side values in an assignment:
_ = x // evaluate x but ignore it x, _ = f() // evaluate f() but ignore second result value
L'affectation se déroule en deux phases. Tout d'abord, les opérandes des expressions d'index a> et pointeur indirections a> (y compris les indirections pointeur implicites dans sélecteurs a>) sur la gauche et les expressions sur la droite sont tous href="#Order_of_evaluation">. Deuxièmement, les missions sont réalisées dans l'ordre de gauche à droite. The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.
a, b = b, a // exchange a and b x := []int{1, 2, 3} i := 0 i, x[i] = 1, 2 // set i = 1, x[0] = 2 i = 0 x[i], i = 2, 1 // set x[0] = 2, i = 1 x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end) x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5. type Point struct { x, y int } var p *Point x[2], p.x = 6, 7 // set x[2] = 6, then panic setting p.x = 7 i = 2 x = []int{3, 5, 7} for i, x[i] = range x { // set i, x[2] = 0, x[0] break } // after this loop, i == 0 and x == []int{3, 5, 3}
Dans missions, chaque valeur doit être assignable a> pour le type de l'opérande à laquelle il est affecté, avec les cas particuliers suivants: In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Si un constante a> est affecté à une variable de type ou l'identifiant vierge interface, la constante est le premier converti a> pour saisir bool tt>, rune tt>, int tt>, float64 tt>, complex128 tt> ou chaîne tt>, respectivement, selon que la valeur est un booléen, rune, entier, virgule flottante, complexe, ou chaîne constante. If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to type bool, rune, int, float64, complex128 or string respectively, depending on whether the value is a boolean, rune, integer, floating-point, complex, or string constant.
Si un côté gauche est l'identificateur vide, tout dactylographiée ou valeur non constante, sauf pour l'identificateur prédéclaré nil a> peut être attribué. If a left-hand side is the blank identifier, any typed or non-constant value except for the predeclared identifier nil may be assigned to it.
"Si" déclarations précisent l'exécution conditionnelle de deux branches en fonction de la valeur d'une expression booléenne. Si l'expression est évaluée à true, le "si" branche est exécutée, sinon, si elle est présente, la branche "else" est exécuté. "If" statements specify the conditional execution of two branches according to the value of a boolean expression. If the expression evaluates to true, the "if" branch is executed, otherwise, if present, the "else" branch is executed.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
if x > max { x = max }
L'expression peut être précédée par une simple déclaration, qui s'exécute avant l'expression est évaluée. The expression may be preceded by a simple statement, which executes before the expression is evaluated.
if x := f(); x < y { return x } else if x > z { return z } else { return y }
Déclarations Switch fournissent l'exécution multi-voies. Une expression ou spécificateur de type est comparée aux «cas» à l'intérieur du "switch" pour déterminer quelle branche à exécuter. "Switch" statements provide multi-way execution. An expression or type specifier is compared to the "cases" inside the "switch" to determine which branch to execute.
SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
Il existe deux formes: commutateurs d'expression et commutateurs de type. Dans un commutateur d'expression, les cas contiennent des expressions qui sont comparées à la valeur de l'expression de l'interrupteur. Dans un commutateur de type, les cas contiennent des types qui sont comparées contre le type d'une expression de switch spécialement annotée. There are two forms: expression switches and type switches. In an expression switch, the cases contain expressions that are compared against the value of the switch expression. In a type switch, the cases contain types that are compared against the type of a specially annotated switch expression.
Dans un commutateur d'expression, l'expression de switch est évaluée et les expressions de cas, qui ne doivent pas être des constantes, sont évalués de gauche à droite et de haut en bas, le premier qui équivaut à l'expression de l'interrupteur déclenche l'exécution des instructions du cas associé, les autres cas sont ignorés. Si aucun cas correspond et il est un cas "par défaut", ses instructions sont exécutées. Il peut y avoir au plus un cas de défaut et il peut apparaître n'importe où dans la déclaration "switch". Une expression de switch manquante est équivalente à l'expression true tt>. In an expression switch, the switch expression is evaluated and the case expressions, which need not be constants, are evaluated left-to-right and top-to-bottom; the first one that equals the switch expression triggers execution of the statements of the associated case; the other cases are skipped. If no case matches and there is a "default" case, its statements are executed. There can be at most one default case and it may appear anywhere in the "switch" statement. A missing switch expression is equivalent to the expression true.
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" . ExprCaseClause = ExprSwitchCase ":" StatementList . ExprSwitchCase = "case" ExpressionList | "default" .
Dans une clause de cas ou par défaut, la dernière déclaration non-vide peut être un (href="#Labeled_statements"> éventuellement ) "fallthrough" déclaration a> pour indiquer que le contrôle devrait découler de la fin de cette clause à la première déclaration de la clause suivante. Sinon contrôle des flux à la fin de la "switch" déclaration. Une déclaration "fallthrough" peut apparaître comme le dernier relevé de tous, mais la dernière phrase d'un commutateur d'expression. In a case or default clause, the last non-empty statement may be a (possibly labeled) "fallthrough" statement to indicate that control should flow from the end of this clause to the first statement of the next clause. Otherwise control flows to the end of the "switch" statement. A "fallthrough" statement may appear as the last statement of all but the last clause of an expression switch.
L'expression peut être précédée par une simple déclaration, qui s'exécute avant l'expression est évaluée. The expression may be preceded by a simple statement, which executes before the expression is evaluated.
switch tag { default: s3() case 0, 1, 2, 3: s1() case 4, 5, 6, 7: s2() } switch x := f(); { // missing switch expression means "true" case x < 0: return -x default: return x } switch { case x < y: f1() case x < z: f2() case x == 4: f3() }
Un commutateur de type compare types plutôt que des valeurs. Il est par ailleurs similaire à un commutateur d'expression. Elle est marquée par une expression particulière de commutation qui a la forme d'une affirmation de type a> en utilisant le mot réservé tapez tt> plutôt que d'un type réel: A type switch compares types rather than values. It is otherwise similar to an expression switch. It is marked by a special switch expression that has the form of a type assertion using the reserved word type rather than an actual type:
switch x.(type) { // cases }
Cas correspondent alors les types réels T tt> contre le type dynamique de l'expression x tt>. Comme avec les assertions de type, x tt> doit être type d'interface a>, et chaque type non interface T tt> figurant dans un cas doivent mettre en œuvre le type de x tt>. Cases then match actual types T against the dynamic type of the expression x. As with type assertions, x must be of interface type, and each non-interface type T listed in a case must implement the type of x.
TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . TypeCaseClause = TypeSwitchCase ":" StatementList . TypeSwitchCase = "case" TypeList | "default" . TypeList = Type { "," Type } .
Le TypeSwitchGuard peut inclure une courte déclaration variables a>. Lorsque cette forme est utilisée, la variable est déclarée au début du bloc implicite a> dans chaque clause. Dans clauses avec un cas énumérant exactement un type, la variable a ce type, sinon la variable est de type de l'expression dans le TypeSwitchGuard. The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the beginning of the implicit block in each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.
Le type dans un cas nil a>, ce cas est utilisé lorsque l'expression dans la TypeSwitchGuard est un nil Interface valeur. The type in a case may be nil; that case is used when the expression in the TypeSwitchGuard is a nil interface value.
Compte tenu de l'expression x tt> de l'interface de type {} tt>, le commutateur de type suivant: Given an expression x of type interface{}, the following type switch:
switch i := x.(type) { case nil: printString("x is nil") // type of i is type of x (interface{}) case int: printInt(i) // type of i is int case float64: printFloat64(i) // type of i is float64 case func(int) float64: printFunction(i) // type of i is func(int) float64 case bool, string: printString("type is bool or string") // type of i is type of x (interface{}) default: printString("don't know the type") // type of i is type of x (interface{}) }
pourrait être réécrite: could be rewritten:
v := x // x is evaluated exactly once if v == nil { i := v // type of i is type of x (interface{}) printString("x is nil") } else if i, isInt := v.(int); isInt { printInt(i) // type of i is int } else if i, isFloat64 := v.(float64); isFloat64 { printFloat64(i) // type of i is float64 } else if i, isFunc := v.(func(int) float64); isFunc { printFunction(i) // type of i is func(int) float64 } else { _, isBool := v.(bool) _, isString := v.(string) if isBool || isString { i := v // type of i is type of x (interface{}) printString("type is bool or string") } else { i := v // type of i is type of x (interface{}) printString("don't know the type") } }
Le commutateur garde de type peut être précédée par une simple déclaration, qui s'exécute avant la garde est évaluée. The type switch guard may be preceded by a simple statement, which executes before the guard is evaluated.
La déclaration "fallthrough" n'est pas autorisée dans un commutateur de type. The "fallthrough" statement is not permitted in a type switch.
A "pour" déclaration définit l'exécution répétée d'un bloc. L'itération est contrôlée par une condition, une clause "for", ou une clause de "gamme". A "for" statement specifies repeated execution of a block. The iteration is controlled by a condition, a "for" clause, or a "range" clause.
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . Condition = Expression .
Dans sa forme la plus simple, un "pour" instruction spécifie l'exécution répétée d'un bloc tant qu'une condition booléenne true. La condition est évaluée avant chaque itération. Si l'état est absent, il est équivalent à true tt>. In its simplest form, a "for" statement specifies the repeated execution of a block as long as a boolean condition evaluates to true. The condition is evaluated before each iteration. If the condition is absent, it is equivalent to true.
for a < b { a *= 2 }
A "pour" déclaration avec un ForClause est également contrôlée par l'état, mais en outre, il peut spécifier un initialisation i> et un poste de i> déclaration, comme une cession, une augmentation ou diminution déclaration. La déclaration d'initialisation peut être une courte déclaration de variable a>, mais la déclaration de poste ne doit pas. A "for" statement with a ForClause is also controlled by its condition, but additionally it may specify an init and a post statement, such as an assignment, an increment or decrement statement. The init statement may be a short variable declaration, but the post statement must not.
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . InitStmt = SimpleStmt . PostStmt = SimpleStmt .
for i := 0; i < 10; i++ { f(i) }
Si non vide, l'instruction d'initialisation est exécutée une fois avant d'évaluer l'état de la première itération, la déclaration de poste est exécuté après chaque exécution du bloc (et seulement si le bloc a été exécuté). Tout élément de la ForClause peut être vide, mais la virgules a> sont requis, sauf si il ya seulement une condition. Si l'état est absent, il est équivalent à true tt>. If non-empty, the init statement is executed once before evaluating the condition for the first iteration; the post statement is executed after each execution of the block (and only if the block was executed). Any element of the ForClause may be empty but the semicolons are required unless there is only a condition. If the condition is absent, it is equivalent to true.
for cond { S() } is the same as for ; cond ; { S() } for { S() } is the same as for true { S() }
A "pour" déclaration d'une «portée» parcourt clause par toutes les entrées d'un tableau, tranche, chaîne ou une carte, ou valeurs reçues sur un canal. Pour chaque entrée, il attribue des valeurs d'itération i> à des variables d'itération i> correspondant, puis exécute le bloc. A "for" statement with a "range" clause iterates through all entries of an array, slice, string or map, or values received on a channel. For each entry it assigns iteration values to corresponding iteration variables and then executes the block.
RangeClause = ( ExpressionList "=" | IdentifierList ":=" ) "range" Expression .
L'expression sur le droit à la clause de «gamme» est appelé l'expression de gamme i>, qui peut être un tableau, pointeur vers un tableau, tranche, ficelle, carte, ou canal permettant opérations de réception a>. Comme une cession, les opérandes de gauche doivent être adressable a> ou carte index des expressions, ils désignent les variables d'itération. Si l'expression de gamme est un canal, une seule variable d'itération est autorisé, sinon il peut y avoir un ou deux. Dans ce dernier cas, si la deuxième variable d'itération est l'identificateur vide a>, la clause de gamme est équivalent à la même clause avec seulement la première variable présente. The expression on the right in the "range" clause is called the range expression, which may be an array, pointer to an array, slice, string, map, or channel permitting receive operations. As with an assignment, the operands on the left must be addressable or map index expressions; they denote the iteration variables. If the range expression is a channel, only one iteration variable is permitted, otherwise there may be one or two. In the latter case, if the second iteration variable is the blank identifier, the range clause is equivalent to the same clause with only the first variable present.
L'expression de gamme est évaluée une fois avant le début de la boucle, à une exception près. Si l'expression de gamme est un tableau ou un pointeur sur un tableau et que la première valeur d'itération est présent, seule la longueur de l'expression de gamme est évaluée, si cette longueur est constante par définition a> , l'expression de gamme se ne sera pas évaluée. The range expression is evaluated once before beginning the loop, with one exception. If the range expression is an array or a pointer to an array and only the first iteration value is present, only the range expression's length is evaluated; if that length is constant by definition, the range expression itself will not be evaluated.
Les appels de fonction sur la gauche sont évaluées une fois par itération. Pour chaque itération, les valeurs d'itération sont produites comme suit: Function calls on the left are evaluated once per iteration. For each iteration, iteration values are produced as follows:
Range expression 1st value 2nd value (if 2nd variable is present) array or slice a [n]E, *[n]E, or []E index i int a[i] E string s string type index i int see below rune map m map[K]V key k K m[k] V channel c chan E, <-chan E element e E
Les valeurs d'itération sont affectées aux variables d'itération respectifs comme dans un instruction d'affectation a>. The iteration values are assigned to the respective iteration variables as in an assignment statement.
Les variables d'itération peuvent être déclarés par la clause "de plage" en utilisant une forme de déclaration variable à court a> (: = tt>). Dans ce cas, leurs types sont définis pour les types des valeurs d'itération respectives et leur champ a> se termine à la fin de la "de" déclaration, ils sont réutilisés à chaque itération . Si les variables d'itération sont déclarées en dehors du "pour" une déclaration, après l'exécution de leurs valeurs seront ceux de la dernière itération. The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope ends at the end of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.
var testdata *struct { a *[7]int } for i, _ := range testdata.a { // testdata.a is never evaluated; len(testdata.a) is constant // i ranges from 0 to 6 f(i) } var a [10]string for i, s := range a { // type of i is int // type of s is string // s == a[i] g(i, s) } var key string var val interface {} // value type of m is assignable to val m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6} for key, val = range m { h(key, val) } // key == last map key encountered in iteration // val == map[key] var ch chan Work = producer() for w := range ch { doWork(w) }
Un "go" déclaration commence l'exécution d'un appel de fonction en tant que thread concurrent indépendant de contrôle, ou goroutine i>, dans le même espace d'adressage. A "go" statement starts the execution of a function call as an independent concurrent thread of control, or goroutine, within the same address space.
GoStmt = "go" Expression .
L'expression doit être une fonction ou appel de méthode, il ne peut pas être mise entre parenthèses. Appels de fonctions intégrées sont limitées que pour les états d'expression a>. The expression must be a function or method call; it cannot be parenthesized. Calls of built-in functions are restricted as for expression statements.
La valeur et les paramètres sont fonction évalué comme d'habitude a> dans le goroutine d'appel, mais à la différence d'un appel normal, l'exécution du programme n'a pas attendu la fonction appelée à compléter. Au lieu de cela, la fonction commence à exécuter de façon autonome dans une nouvelle goroutine. Lorsque la fonction se termine, son goroutine termine également. Si la fonction a des valeurs de retour, ils sont mis au rebut lorsque la fonction se termine. The function value and parameters are evaluated as usual in the calling goroutine, but unlike with a regular call, program execution does not wait for the invoked function to complete. Instead, the function begins executing independently in a new goroutine. When the function terminates, its goroutine also terminates. If the function has any return values, they are discarded when the function completes.
go Server() go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)
Une déclaration ", sélectionnez" choisit parmi un ensemble de communications possibles se déroulera. Il ressemble à une instruction "switch" mais avec des cas tout se référant à des opérations de communication. A "select" statement chooses which of a set of possible communications will proceed. It looks similar to a "switch" statement but with the cases all referring to communication operations.
SelectStmt = "select" "{" { CommClause } "}" . CommClause = CommCase ":" StatementList . CommCase = "case" ( SendStmt | RecvStmt ) | "default" . RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr . RecvExpr = Expression .
RecvExpr doit être un opération de réception a> . Pour tous les cas dans l' instruction «select» , les expressions de canaux sont évaluées dans l'ordre de haut en bas, avec des expressions qui apparaissent sur le côté droit des états d'envoi . Un canal peut être nul tt> , qui est équivalent à ce cas de ne pas être présent dans l'instruction select , sauf si une émission , son expression est toujours évaluée . Si l'une des opérations résultant peut procéder , l'un de ceux est choisi et la communication et les états correspondant sont évalués. Sinon, si il ya un cas de défaut , qui exécute , si il n'ya pas de cas de défaut , les blocs d'instructions jusqu'à ce que l'une des communications peuvent compléter . Il peut y avoir au plus un cas de défaut et il peut apparaître n'importe où dans la « select» . Si il n'ya pas de cas avec des non- néant tt> canaux , les blocs d'instructions toujours. Même si les blocs d'instructions , le canal et envoyer les expressions sont évaluées qu'une seule fois , à l'entrée de l'instruction select . RecvExpr must be a receive operation. For all the cases in the "select" statement, the channel expressions are evaluated in top-to-bottom order, along with any expressions that appear on the right hand side of send statements. A channel may be nil, which is equivalent to that case not being present in the select statement except, if a send, its expression is still evaluated. If any of the resulting operations can proceed, one of those is chosen and the corresponding communication and statements are evaluated. Otherwise, if there is a default case, that executes; if there is no default case, the statement blocks until one of the communications can complete. There can be at most one default case and it may appear anywhere in the "select" statement. If there are no cases with non-nil channels, the statement blocks forever. Even if the statement blocks, the channel and send expressions are evaluated only once, upon entering the select statement.
Comme tous les canaux et envoyer les expressions sont évaluées, les effets secondaires de cette évaluation auront lieu pour toutes les communications de l'instruction «select». Since all the channels and send expressions are evaluated, any side effects in that evaluation will occur for all the communications in the "select" statement.
Si plusieurs cas peuvent procéder, un choix de pseudo-aléatoire uniforme est fait de décider qui va exécuter communication unique. Le cas de réception peut déclarer une ou deux nouvelles variables en utilisant une courte déclaration variables a>. If multiple cases can proceed, a uniform pseudo-random choice is made to decide which single communication will execute. The receive case may declare one or two new variables using a short variable declaration.
var c, c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: print("received ", i1, " from c1\n") case c2 <- i2: print("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { print("received ", i3, " from c3\n") } else { print("c3 is closed\n") } default: print("no communication\n") } for { // send random sequence of bits to c select { case c <- 0: // note: no statement, no fallthrough, no folding of cases case c <- 1: } } select {} // block forever
Un "return" dans une fonction F tt> termine l'exécution de F tt>, et éventuellement fournit une ou plusieurs valeurs de résultats. Toute fonctions différé a> par F tt> sont exécutés avant F tt> retourne à son appelant. A "return" statement in a function F terminates the execution of F, and optionally provides one or more result values. Any functions deferred by F are executed before F returns to its caller.
ReturnStmt = "return" [ ExpressionList ] .
Dans une fonction sans type de résultat, une déclaration "de retour" ne doit pas spécifier les valeurs de résultat. In a function without a result type, a "return" statement must not specify any result values.
func noResult() { return }
Il ya trois façons de retourner des valeurs d'une fonction avec un type de résultat: There are three ways to return values from a function with a result type:
func simpleF() int { return 2 } func complexF1() (re float64, im float64) { return -7.0, -4.0 }
func complexF2() (re float64, im float64) { return complexF1() }
func complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return } func (devnull) Write(p []byte) (n int, _ error) { n = len(p) return }
Indépendamment de la façon dont ils sont déclarés, toutes les valeurs de résultat sont initialisés à la valeurs nulles a> pour leur type lors de l'entrée à la fonction. Un "retour" déclaration qui spécifie les résultats définit les paramètres de résultat avant des fonctions différés sont exécutées. Regardless of how they are declared, all the result values are initialized to the zero values for their type upon entry to the function. A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
Un "break" déclaration met fin à l'exécution de la "pour" a>, "switch" a>, ou ", sélectionnez " a> déclaration. A "break" statement terminates execution of the innermost "for", "switch", or "select" statement.
BreakStmt = "break" [ Label ] .
Si il ya une étiquette, il faut que d'une enceinte "pour", "switch", ou "sélectionner" déclaration, et qui est celui dont l'exécution se termine. If there is a label, it must be that of an enclosing "for", "switch", or "select" statement, and that is the one whose execution terminates.
OuterLoop: for i = 0; i < n; i++ { for j = 0; j < m; j++ { switch a[i][j] { case nil: state = Error break OuterLoop case item: state = Found break OuterLoop } } }
Un "continuer" déclaration commence la prochaine itération de la boucle "for" a> à sa déclaration de poste. A "continue" statement begins the next iteration of the innermost "for" loop at its post statement.
ContinueStmt = "continue" [ Label ] .
Si il ya une étiquette, il faut que d'une enceinte "pour" déclaration, et qui est celui dont les progrès exécution. If there is a label, it must be that of an enclosing "for" statement, and that is the one whose execution advances.
RowLoop: for y, row := range rows { for x, data := range row { if data == endOfRow { continue RowLoop } row[x] = data + bias(x, y) } }
A "goto" transferts d'états de contrôle de la déclaration avec l'étiquette correspondante. A "goto" statement transfers control to the statement with the corresponding label.
GotoStmt = "goto" Label .
goto Error
Exécution de l'instruction "goto" ne doit pas causer de variables entrent en champ a> qui n'étaient pas déjà dans la portée au point de le goto. Par exemple, l'exemple suivant: Executing the "goto" statement must not cause any variables to come into scope that were not already in scope at the point of the goto. For instance, this example:
goto L // BAD v := 3 L:
est erronée parce que le saut à l'étiquette L tt> saute la création de v tt>. is erroneous because the jump to label L skips the creation of v.
Un "goto" déclaration extérieur d'un bloc a> ne peut pas sauter à une étiquette à l'intérieur de ce bloc. Par exemple, l'exemple suivant: A "goto" statement outside a block cannot jump to a label inside that block. For instance, this example:
if n%2 == 1 { goto L1 } for n > 0 { f() n-- L1: f() n-- }
est erronée parce que l'étiquette L1 tt> est à l'intérieur du «pour» le bloc de déclaration, mais le goto tt> est pas. is erroneous because the label L1 is inside the "for" statement's block but the goto is not.
A transfère l'"fallthrough" contrôlent à la première déclaration de la clause de cas suivante dans une expression "switch" de déclaration a>. Il peut être utilisé seulement comme la déclaration finale non vide dans une telle clause. A "fallthrough" statement transfers control to the first statement of the next case clause in a expression "switch" statement. It may be used only as the final non-empty statement in such a clause.
FallthroughStmt = "fallthrough" .
Un "defer" déclaration appelle une fonction dont l'exécution est reportée à l'instant la fonction retourne environnantes, soit parce que la fonction exécutée entourant une déclaration de retour a>, a atteint la fin de sa corps de la fonction a>, ou parce que le goroutine correspondant est paniquer a>. A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.
DeferStmt = "defer" Expression .
L'expression doit être une fonction ou appel de méthode, il ne peut pas être mise entre parenthèses. Appels de fonctions intégrées sont limitées que pour les états d'expression a>. The expression must be a function or method call; it cannot be parenthesized. Calls of built-in functions are restricted as for expression statements.
Chaque fois que le "defer" instruction s'exécute, la valeur et les paramètres de la fonction d'appel sont évaluée comme d'habitude a> et enregistré à nouveau mais le corps de la fonction réelle n'est pas exécuté. Au lieu de cela, les fonctions différés sont exécutées immédiatement avant le retour de la fonction environnantes, dans l'ordre inverse de leur reportés. Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function body is not executed. Instead, deferred functions are executed immediately before the surrounding function returns, in the reverse order they were deferred.
Par exemple, si la fonction différée est une fonction littérale a> et la fonction environnante est paramètres de résultat nommée a> qui sont dans la portée dans le, la fonction différée littérale peut accéder et modifier les paramètres de résultat avant qu'ils soient retournés. Si la fonction a reporté les valeurs de retour, ils sont mis au rebut lorsque la fonction se termine. (Voir aussi la section sur manipulation panique a>.) For instance, if the deferred function is a function literal and the surrounding function has named result parameters that are in scope within the literal, the deferred function may access and modify the result parameters before they are returned. If the deferred function has any return values, they are discarded when the function completes. (See also the section on handling panics.)
lock(l) defer unlock(l) // unlocking happens before surrounding function returns // prints 3 2 1 0 before surrounding function returns for i := 0; i <= 3; i++ { defer fmt.Print(i) } // f returns 1 func f() (result int) { defer func() { result++ }() return 0 }
Les fonctions intégrées sont prédéclaré a>. Ils sont appelés comme toute autre fonction, mais certains d'entre eux acceptent un type à la place d'une expression comme premier argument. Built-in functions are predeclared. They are called like any other function but some of them accept a type instead of an expression as the first argument.
Les fonctions intégrées n'ont pas les types Go standard, de sorte qu'ils ne peuvent apparaître dans appel expressions a>, ils ne peuvent pas être utilisés comme valeurs de fonction. The built-in functions do not have standard Go types, so they can only appear in call expressions; they cannot be used as function values.
BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" . BuiltinArgs = Type [ "," ArgumentList ] | ArgumentList .
Pour un canal c tt>, la clôture de la fonction intégrée (c) tt> documents qui ne seront plus les valeurs envoyés sur le canal. C'est une erreur si c tt> est un canal de réception seulement. Envoi ou la fermeture d'un canal fermé provoque une panique panique d'exécution. Fermeture du canal zéro provoque également une panique d'exécution a>. Après l'appel près tt>, et après toutes les valeurs précédemment envoyées ont été reçues, reçoivent opérations seront de retour la valeur zéro pour le type de canal sans blocage. Les valeurs multiples reçoivent opération a> retourne une valeur reçue avec une indication du fait que le canal est fermé. For a channel c, the built-in function close(c) records that no more values will be sent on the channel. It is an error if c is a receive-only channel. Sending to or closing a closed channel causes a run-time panic. Closing the nil channel also causes a run-time panic. After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking. The multi-valued receive operation returns a received value along with an indication of whether the channel is closed.
Les fonctions intégrées len tt> et cap tt> prennent des arguments de différents types et renvoient un résultat de type int tt>. La mise en œuvre garantit que le résultat va toujours dans un int tt>. The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int.
Appel Type d'argument Résultat len(s) string type string length in bytes [n]T, *[n]T array length (== n) []T slice length map[K]T map length (number of defined keys) chan T number of elements queued in channel buffer cap(s) [n]T, *[n]T array length (== n) []T slice capacity chan T channel buffer capacity
La capacité d'une tranche est le nombre d'éléments pour lesquels il existe un espace alloué dans la matrice sous-jacente. A tout moment, la relation suivante est vérifiée: The capacity of a slice is the number of elements for which there is space allocated in the underlying array. At any time the following relationship holds:
0 <= len(s) <= cap(s)
La longueur d'un nil tranche, la carte ou le canal est de 0. La capacité d'un nil tranche et le canal est de 0. The length of a nil slice, map or channel is 0. The capacity of a nil slice and channel is 0.
L'expression len (s) tt> est constante a> si s tt> est une chaîne constante. Les expressions len (s) tt> et bouchon (s) tt> sont des constantes si le type de s tt> est un tableau ou un pointeur vers un tableau et l'expression s tt> ne contient pas canal reçoit a> ou la fonction appelle a>, dans ce cas s tt> n'est pas évalué. Sinon, les appels de len tt> et cap tt> ne sont pas constants et s tt> est évalué. The expression len(s) is constant if s is a string constant. The expressions len(s) and cap(s) are constants if the type of s is an array or pointer to an array and the expression s does not contain channel receives or function calls; in this case s is not evaluated. Otherwise, invocations of len and cap are not constant and s is evaluated.
La fonction intégrée nouveau tt> prend un type T tt> et retourne une valeur de type * T tt>. La mémoire est initialisée comme décrit dans la section sur valeurs initiales a>. The built-in function new takes a type T and returns a value of type *T. The memory is initialized as described in the section on initial values.
new(T)
par exemple
type S struct { a int; b float64 } new(S)
alloue dynamiquement la mémoire pour une variable de type S tt>, initialise ( a = 0, b = 0,0 tt> tt>), et renvoie une valeur de type * S tt> contenant l'adresse de la mémoire. dynamically allocates memory for a variable of type S, initializes it (a=0, b=0.0), and returns a value of type *S containing the address of the memory.
La fonction intégrée faire tt> prend un type T tt>, qui doit être une tranche, la carte ou le type de canal, éventuellement suivie d'une liste d'expressions de type spécifique. Elle renvoie une valeur de type T tt> (pas * T tt>). La mémoire est initialisée comme décrit dans la section sur valeurs initiales a>. The built-in function make takes a type T, which must be a slice, map or channel type, optionally followed by a type-specific list of expressions. It returns a value of type T (not *T). The memory is initialized as described in the section on initial values.
Call Type T Result make(T, n) slice slice of type T with length n and capacity n make(T, n, m) slice slice of type T with length n and capacity m make(T) map map of type T make(T, n) map map of type T with initial space for n elements make(T) channel synchronous channel of type T make(T, n) channel asynchronous channel of type T, buffer size n
Les arguments de taille n tt> et m tt> doit être de type entier ou non typé. Une constante argument de taille doit être non négatif et représentable par une valeur de type int tt>. Si les deux n tt> et m tt> sont fournies et sont constants, alors n tt> doit pas être supérieure à m tt>. Si n tt> est négatif ou plus grand que m tt> au moment de l'exécution, une panique d'exécution se produit. The size arguments n and m must be of integer type or untyped. A constant size argument must be non-negative and representable by a value of type int. If both n and m are provided and are constant, then n must be no larger than m. If n is negative or larger than m at run time, a run-time panic occurs.
s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100 s := make([]int, 1e3) // slice with len(s) == cap(s) == 1000 s := make([]int, 1<<63) // illegal: len(s) is not representable by a value of type int s := make([]int, 10, 0) // illegal: len(s) > cap(s) c := make(chan int, 10) // channel with a buffer size of 10 m := make(map[string]int, 100) // map with initial space for 100 elements
Les fonctions intégrées append tt> et copie tt> aider dans les opérations de découpe communes. Pour les deux fonctions, le résultat est indépendant du fait que la mémoire référencée par les arguments chevauche. The built-in functions append and copy assist in common slice operations. For both functions, the result is independent of whether the memory referenced by the arguments overlaps.
Le href="#Function_types"> variadique a> fonction append tt> ajoute zéro ou plusieurs valeurs x tt> pour s tt> de Type S tt>, qui doit être un type de tranche, et renvoie la tranche obtenue, également de type S tt>. Les valeurs x tt> sont passés à un paramètre de type ... T tt> où T tt> est le type d'élément a> de S tt> et règles de passage de paramètres a> s'applique. Comme un cas particulier, append tt> accepte aussi un premier argument assignable à taper [] octet tt> avec un second argument de type chaîne de caractères suivie par ... tt> . Cette forme ajoute les octets de la chaîne. The variadic function append appends zero or more values x to s of type S, which must be a slice type, and returns the resulting slice, also of type S. The values x are passed to a parameter of type ...T where T is the element type of S and the respective parameter passing rules apply. As a special case, append also accepts a first argument assignable to type []byte with a second argument of string type followed by .... This form appends the bytes of the string.
append(s S, x ...T) S // T is the element type of S
Si la capacité de s tt> n'est pas assez grand pour accueillir les valeurs supplémentaires, append tt> alloue un nouveau suffisamment grand tableau, sous-jacente qui correspond à la fois les éléments de tranches existantes et les valeurs supplémentaires. Sinon, append tt> re-utilise le réseau sous-jacent. If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.
s0 := []int{0, 0} s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2} s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7} s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3, 5, 7, 0, 0} s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0} var t []interface{} t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"} var b []byte b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
La fonction copier tt> éléments copies de tranche d'une source src tt> pour une destination dst tt> et renvoie le nombre d'éléments copiés. Les deux arguments doivent avoir identique a> type d'élément T tt> et doit être assignable a> pour une tranche de Type [] T tt>. Le nombre d'éléments copiés est le minimum de len (src) tt> et len (dst) tt>. Comme un cas particulier, copie tt> accepte aussi un argument de destination assignable à taper [] octet tt> avec un argument source d'un type de chaîne. Ce formulaire copies du octets de la chaîne dans la tranche d'octets. The function copy copies slice elements from a source src to a destination dst and returns the number of elements copied. Both arguments must have identical element type T and must be assignable to a slice of type []T. The number of elements copied is the minimum of len(src) and len(dst). As a special case, copy also accepts a destination argument assignable to type []byte with a source argument of a string type. This form copies the bytes from the string into the byte slice.
copy(dst, src []T) int copy(dst []byte, src string) int
Exemples:
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7} var s = make([]int, 6) var b = make([]byte, 5) n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5} n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5} n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
La fonction intégrée supprimer tt> supprime l'élément avec la clé k tt> à partir d'une carte a> m tt> . Le type de k tt> doit être assignable a> pour le type de clé de m tt>. The built-in function delete removes the element with key k from a mapm. The type of k must be assignable to the key type of m.
delete(m, k) // remove element m[k] from map m
Si la carte m tt> est nil ou l'élément m [k] tt> n'existe pas, supprimer tt> est un non-op. If the map m is nil or the element m[k] does not exist, delete is a no-op.
Trois fonctions monter et démonter des nombres complexes. La fonction intégrée complexe tt> construit une valeur complexe d'une partie à virgule flottante réel et l'imaginaire, tout réel tt> et imag tt> extraire le réel et l'imaginaire pièces d'une valeur complexe. Three functions assemble and disassemble complex numbers. The built-in function complex constructs a complex value from a floating-point real and imaginary part, while real and imag extract the real and imaginary parts of a complex value.
complex(realPart, imaginaryPart floatT) complexT real(complexT) floatT imag(complexT) floatT
Le type des arguments et de la valeur de retour correspondent. Pour complexe tt>, les deux arguments doivent être de même type à virgule flottante et le type de retour est le type complexe avec les mandants à virgule flottante correspondant: complex64 tt> pour float32 tt>, complex128 tt> pour float64 tt>. La vraie tt> et imag tt> fonctions forment ensemble l'inverse, si pour une valeur complexe z tt>, z tt> = = tt> complexe (réel (z), tt> imag (z)) tt>. The type of the arguments and return value correspond. For complex, the two arguments must be of the same floating-point type and the return type is the complex type with the corresponding floating-point constituents: complex64 for float32, complex128 for float64. The real and imag functions together form the inverse, so for a complex value z, z==complex(real(z),imag(z)).
Si les opérandes de ces fonctions sont toutes des constantes, la valeur de retour est une constante. If the operands of these functions are all constants, the return value is a constant.
var a = complex(2, -2) // complex128 var b = complex(1.0, -1.4) // complex128 x := float32(math.Cos(math.Pi/2)) // float32 var c64 = complex(5, -x) // complex64 var im = imag(b) // float64 var rl = real(c64) // float32
Deux fonctions intégrées, panic et recover, aident dans les rapports et la gestion des paniques d'exécution et programme défini les conditions d'erreur. Two built-in functions, panic and recover, assist in reporting and handling run-time panics and program-defined error conditions.
func panic(interface{}) func recover() interface{}
Pendant l'exécution d'une fonction F tt>, un appel explicite à panic ou une panique d'exécution termine l'exécution de F tt>. Toute fonctions différé a> par F tt> sont alors exécuté comme d'habitude. Ensuite, toutes les fonctions différés gérés par tt> l'appelant de F sont exécutés, et ainsi de suite jusqu'à tout reporté par la fonction de haut niveau dans le goroutine exécution. À ce moment, le programme est terminé et la condition d'erreur est signalée, y compris la valeur de l'argument de panique tt>. Cette séquence de terminaison est appelé paniquer i>. While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking.
panic(42) panic("unreachable") panic(Error("cannot parse"))
Les récupérer tt> permet un programme pour gérer le comportement d'un goroutine de panique. Supposons une fonction G tt> reporte une fonction D tt> qui appelle récupérer tt> et la panique se produit dans une fonction sur le même goroutine dans lequel G tt> est l'exécution. Lorsque le déroulement des fonctions différés atteint D tt>, la valeur de retour de D tt> de l 'appel à récupérer tt> sera la valeur passée à l'appel de panique tt>. Si D tt> retourne normalement, sans lancer une nouvelle panique tt>, la séquence s'arrête à paniquer. Dans ce cas, l'état de fonctions appelées entre G tt> et l'appel à panique tt> est rejeté, et l'exécution normale reprend. Toutes les fonctions reportées par G tt> avant D tt> sont ensuite exécutés et G tt> de l 'exécution se termine par un retour à l'appelant. The recover function allows a program to manage behavior of a panicking goroutine. Suppose a function G defers a function D that calls recover and a panic occurs in a function on the same goroutine in which G is executing. When the running of deferred functions reaches D, the return value of D's call to recover will be the value passed to the call of panic. If D returns normally, without starting a new panic, the panicking sequence stops. In that case, the state of functions called between G and the call to panic is discarded, and normal execution resumes. Any functions deferred by G before D are then run and G's execution terminates by returning to its caller.
La valeur de retour de recover est tt>nil si l'une des conditions suivantes est remplie: The return value of recover is nil if any of the following conditions holds:
La fonction protect dans l'exemple ci-dessous invoque l'argument de la fonction g et protège les appelants des panique d'exécution provoquées par g.
func protect(g func()) { defer func() { log.Println("done") // Println executes normally even if there is a panic if x := recover(); x != nil { log.Printf("run time panic: %v", x) } }() log.Println("start") g() }
Les implémentations actuelles offrent plusieurs fonctions intégrées utiles lors de l'amorçage. Ces fonctions sont documentées par souci d'exhaustivité, mais ne sont pas garantis de rester dans la langue. Ils ne renvoient pas de résultat. Current implementations provide several built-in functions useful during bootstrapping. These functions are documented for completeness but are not guaranteed to stay in the language. They do not return a result.
Function Behavior print prints all arguments; formatting of arguments is implementation-specific println like print but prints spaces between arguments and a newline at the end
Aller programmes sont construits en reliant paquets i>. Un forfait à son tour est construite à partir d'un ou plusieurs fichiers sources qui déclarent ensemble des constantes, des types, des variables et des fonctions appartenant à l'ensemble et qui sont accessibles à tous les fichiers d'un même forfait. Ces éléments peuvent être exporté a> et utilisé dans un autre paquet. Go programs are constructed by linking together packages. A package in turn is constructed from one or more source files that together declare constants, types, variables and functions belonging to the package and which are accessible in all files of the same package. Those elements may be exported and used in another package.
Chaque fichier source est constituée d'une clause de paquet définissant l'ensemble auquel il appartient, suivi par un ensemble éventuellement vide des déclarations d'importation qui déclarent les paquets dont il souhaite utiliser, puis par un ensemble éventuellement vide des déclarations de fonctions, types, variables, et des constantes. Each source file consists of a package clause defining the package to which it belongs, followed by a possibly empty set of import declarations that declare packages whose contents it wishes to use, followed by a possibly empty set of declarations of functions, types, variables, and constants.
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
Une clause de paquetage commence chaque fichier source et définit le package auquel appartient le fichier. A package clause begins each source file and defines the package to which the file belongs.
PackageClause = "package" PackageName . PackageName = identifier .
Le PackageName ne doit pas être l'identifiant blank. The PackageName must not be the blank identifier.
package math
Un ensemble de partage de fichiers former la même PackageName la mise en œuvre d'un paquet. Une mise en œuvre peut exiger que tous les fichiers sources pour un paquet habitent le même répertoire. A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.
Une déclaration d'importation indique que le fichier source contenant la déclaration dépend de la fonctionnalité de la importée i> paquet ( initialisation et l'exécution a>) et permet d'accéder à Exported_identifiers exportés a> identificateurs de ce paquet. Les noms d'importation d'un identifiant (PackageName) à être utilisé pour l'accès et un ImportPath qui spécifie le package à importer. An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported.
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) . ImportSpec = [ "." | PackageName ] ImportPath . ImportPath = string_lit .
Le PackageName est utilisé dans identificateurs qualifiés a> à des identifiants d'accès exporté du colis se trouvant dans le fichier source d'importation. Il est déclaré dans le bloc de fichier a>. Si le PackageName est omis, sa valeur par défaut à l'identifiant spécifié dans le href="#Package_clause"> clause de forfait du package importé. Si une période explicite (. Tt>) apparaît à la place d'un nom, tous les identificateurs exportés de l'emballage déclarés dans paquet bloc de ce paquet a> seront déclarés dans l'importation le bloc et de fichier de fichier source peut être consulté sans qualificatif. The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file. It is declared in the file block. If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package. If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source file's file block and can be accessed without a qualifier.
L'interprétation de la ImportPath dépend de l'implémentation, mais il est généralement une sous-chaîne du nom complet du fichier du paquet compilé et peut-être par rapport à un référentiel de packages installés. The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.
Restriction de mise en œuvre: Un compilateur peut restreindre ImportPaths à chaînes non vides en utilisant uniquement des caractères appartenant à de L de href="http://www.unicode.org/versions/Unicode6.2.0/"> Unicode, M, N, P, S et catégories générales (les caractères graphiques sans espaces) et peuvent aussi exclure les caractères "# $% & '() *,:;? <=> [\] ^` {|} tt> et le caractère de remplacement Unicode U + FFFD. Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to Unicode's L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character U+FFFD.
Supposons que nous avons compilé un paquet contenant le package mathématiques clause de forfait tt>, qui exporte la fonction Sin tt>, et installé le paquet compilé dans le fichier identifié par "lib / math" tt>. Ce tableau illustre comment Sin tt> peut être consulté dans les dossiers qui importent le paquet après les différents types de déclaration d'importation. Assume we have compiled a package containing the package clause package math, which exports function Sin, and installed the compiled package in the file identified by "lib/math". This table illustrates how Sin may be accessed in files that import the package after the various types of import declaration.
Import declaration Local name of Sin import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
Une déclaration d'importation déclare une relation de dépendance entre le pays importateur et package importé. Il est illégal pour un paquet à lui-même importer, directement ou indirectement, ou d'importer directement un paquet sans se référer à l'une de ses identifiants exportés. Pour importer un package uniquement à ses effets secondaires (initialisation), utilisez les blanc a> identifiant aussi explicite nom du paquet: An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:
import _ "lib/math"
Voici un paquet Go complet qui implémente un tamis premier concurrent. Here is a complete Go package that implements a concurrent prime sieve.
package main import "fmt" // Send the sequence 2, 3, 4, … to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'src' to channel 'dst', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i // Send 'i' to channel 'dst'. } } } // The prime sieve: Daisy-chain filter processes together. func sieve() { ch := make(chan int) // Create a new channel. go generate(ch) // Start generate() as a subprocess. for { prime := <-ch fmt.Print(prime, "\n") ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1 } } func main() { sieve() }
Lorsque la mémoire est allouée pour stocker une valeur, soit par une déclaration ou un appel de faire tt> ou nouveau tt>, et aucune initialisation explicite est fourni, la mémoire est donnée une initialisation par défaut. Chaque élément de cette valeur est définie à la valeur de zéro i> pour son type: false tt> pour les booléens, 0 tt> pour les entiers, 0.0 tt> pour les flotteurs, "" tt> pour les chaînes, et nil pour les pointeurs, les fonctions, les interfaces, les tranches, les canaux, et des cartes. Cette initialisation se fait de manière récursive, de sorte, par exemple, chaque élément d'un tableau de structures aura ses champs mis à zéro si aucune valeur n'est spécifiée. When memory is allocated to store a value, either through a declaration or a call of make or new, and no explicit initialization is provided, the memory is given a default initialization. Each element of such a value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.
Ces deux déclarations simples sont équivalentes :
var i int var i int = 0
Après :
type T struct { i int; f float64; next *T } t := new(T)
la variable contient :
t.i == 0 t.f == 0.0 t.next == nil
La même chose pourrait aussi être vraie après :
var t T
Un paquet avec aucun importations est initialisée en affectant des valeurs initiales de toutes ses variables au niveau de l'emballage et d'appeler une fonction de niveau package avec le nom et la signature de puis A package with no imports is initialized by assigning initial values to all its package-level variables and then calling any package-level function with the name and signature of
func init()
défini dans la source. Un paquet-cadre ou un fichier-champ identifiant avec le nom initialisation tt> ne peut être considéré comme une fonction à cette signature. Ces fonctions multiples peuvent être définies, même au sein d'un seul fichier source, ils s'exécutent dans un ordre non spécifié. defined in its source. A package-scope or file-scope identifier with name init may only be declared to be a function with this signature. Multiple such functions may be defined, even within a single source file; they execute in unspecified order.
Dans un package, les variables de niveau package sont initialisés, et des valeurs constantes sont déterminées, selon l'ordre de renvoi: si l'initialiseur de A tt> dépend B tt>, A tt> sera fixé après B tt>. Dépendance analyse ne dépend pas des valeurs réelles des éléments en cours d'initialisation, uniquement sur leur apparence dans la source. A tt> dépend B tt> si la valeur de A tt> contient une mention de B tt>, contient une valeur dont initialisation mentionne B tt>, ou mentionne une fonction qui mentionne B tt>, de manière récursive. C'est une erreur si ces dépendances forment un cycle. Si deux éléments ne sont pas interdépendantes, elles seront initialisées dans l'ordre où ils apparaissent dans la source, peut-être dans plusieurs fichiers, tel que présenté par le compilateur. Depuis l'analyse de dépendance se fait par paquet, il peut produire des résultats non précisées si A tt> de l 'initialisation appelle une fonction définie dans un autre package qui fait référence à B tt>. Within a package, package-level variables are initialized, and constant values are determined, according to order of reference: if the initializer of A depends on B, A will be set after B. Dependency analysis does not depend on the actual values of the items being initialized, only on their appearance in the source. A depends on B if the value of A contains a mention of B, contains a value whose initializer mentions B, or mentions a function that mentions B, recursively. It is an error if such dependencies form a cycle. If two items are not interdependent, they will be initialized in the order they appear in the source, possibly in multiple files, as presented to the compiler. Since the dependency analysis is done per package, it can produce unspecified results if A's initializer calls a function defined in another package that refers to B.
Une fonction init ne peut pas être appelé de n'importe où dans un programme. En particulier, initialisation tt> ne peut pas être appelé explicitement, ni un pointeur vers init être affecté à une variable de la fonction. An init function cannot be referred to from anywhere in a program. In particular, init cannot be called explicitly, nor can a pointer to init be assigned to a function variable.
Si un paquet importations, les paquets importés sont initialisés avant d'initialiser le paquet lui-même. Si plusieurs packages importer un package P tt>, P tt> est initialisée qu'une seule fois. If a package has imports, the imported packages are initialized before initializing the package itself. If multiple packages import a package P, P will be initialized only once.
L'importation de paquets, par construction, garantit qu'il ne peut y avoir aucune dépendances cycliques dans l'initialisation. The importing of packages, by construction, guarantees that there can be no cyclic dependencies in initialization.
Un programme complet est créé en reliant un seul paquet unimported appelé le paquet principal i> avec tous les paquets qu'elle importe, transitive. Le paquet principal doit avoir le nom de paquet principale tt> et déclarer une fonction principale tt> qui ne prend aucun argument et ne retourne aucune valeur. A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. The main package must have package name main and declare a function main that takes no arguments and returns no value.
func main() { … }
L'exécution du programme commence par initialiser le paquet principal puis en appelant la fonction principale tt>. Lorsque la fonction principales tt> rendement, le programme se termine. Il n'attend pas pour d'autres (non- principale tt>) goroutines à compléter. Program execution begins by initializing the main package and then invoking the function main. When the function main returns, the program exits. It does not wait for other (non-main) goroutines to complete.
Package initialisation variable initialisation et l'invocation de initialisation tt> fonctions-qui se passe dans un seul goroutine, séquentiellement, un paquet à la fois. Un tt> initialisation peut lancer d'autres goroutines, qui peut fonctionner en même temps que le code d'initialisation. Cependant, l'initialisation des séquences toujours les initialisation tt> fonctions: il ne démarre pas la prochaine initialisation tt> jusqu'à ce que la précédente a retourné. Package initialization—variable initialization and the invocation of init functions—happens in a single goroutine, sequentially, one package at a time. An init function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences the init functions: it will not start the next init until the previous one has returned.
Le type prédéclaré error est défini comme The predeclared type error is defined as
type error interface { Error() string }
Il s'agit de l'interface conventionnelle pour représenter une condition d'erreur, par la valeur nulle représentant pas d'erreur. Par exemple, une fonction pour lire les données à partir d'un fichier peut être définie: It is the conventional interface for representing an error condition, with the nil value representing no error. For instance, a function to read data from a file might be defined:
func Read(f *File, b []byte) (n int, err error)
Les fautes d'exécution telles que la tentative à l'index d'un tableau en dehors des limites de déclencher une panique exécution i> équivalent à un appel de la panique de la fonction intégrée tt> a> avec une valeur du type défini par l'implémentation d'interface runtime.Error tt>. Ce type satisfait l'erreur du prédéclaré type d'interface tt> a>. Les valeurs d'erreur exact qui représentent des conditions d'erreur d'exécution distinctes ne sont pas précisés. Execution errors such as attempting to index an array out of bounds trigger a run-time panic equivalent to a call of the built-in function panic with a value of the implementation-defined interface type runtime.Error. That type satisfies the predeclared interface type error. The exact error values that represent distinct run-time error conditions are unspecified.
package runtime type Error interface { error // et peut-être d'autres méthodes }
Le paquet intégré unsafe, connu pour le compilateur, offre des services de programmation de bas niveau, y compris les opérations qui violent le système de type. Un package à l'aide dangereux tt> doit être contrôlé manuellement pour la sécurité de type. Le paquet fournit l'interface suivante: The built-in package unsafe, known to the compiler, provides facilities for low-level programming including operations that violate the type system. A package using unsafe must be vetted manually for type safety. The package provides the following interface:
package unsafe type ArbitraryType int // raccourci pour n'importe quel type Go, ce n'est pas un type réel type Pointer *ArbitraryType func Alignof(variable ArbitraryType) uintptr func Offsetof(selector ArbitraryType) uintptr func Sizeof(variable ArbitraryType) uintptr
Toute pointeur ou de la valeur de type sous-jacent a> UIntPtr tt> peuvent être convertis en un Pointer tt> type et vice versa. Un Pointer tt> est un type pointeur a>, mais un pointeur tt> valeur ne peuvent pas être déréférencé a>. Any pointer or value of underlying typeuintptr can be converted to a Pointer type and vice versa. A Pointer is a pointer type but a Pointer value may not be dereferenced.
var f float64 bits = *(*uint64)(unsafe.Pointer(&f)) type ptr unsafe.Pointer bits = *(*uint64)(ptr(&f)) var p ptr = nil
Les fonctions alignof tt> et Sizeof tt> prennent une expression x tt> de tout type et de retour de l'alignement ou la taille, respectivement, d'un hypothétique variables v tt> comme si v tt> a été déclarée par var v = x tt>. The functions Alignof and Sizeof take an expression x of any type and return the alignment or size, respectively, of a hypothetical variable v as if v was declared via var v = x.
La fonction offsetof tt> prend une (éventuellement entre parenthèses) sélecteur a> sf tt>, désignant un champ f tt> de la structure désignée par s tt> ou * s tt>, et renvoie le champ de décalage en octets par rapport à l'adresse de la structure. Si f tt> est un de domaine intégré a>, il doit être accessible sans indirections pointeur à travers les champs de la structure. Pour une structure s tt> avec le champ f tt>: The function Offsetof takes a (possibly parenthesized) selectors.f, denoting a field f of the struct denoted by s or *s, and returns the field offset in bytes relative to the struct's address. If f is an embedded field, it must be reachable without pointer indirections through fields of the struct. For a struct s with field f:
uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))
Architectures informatiques peuvent nécessiter traite mémoire à aligné i>, c'est pour les adresses d'une variable à un multiple d'un facteur, l'alignement le type de la variable i>. La fonction alignof tt> prend une expression désignant une variable de n'importe quel type et retourne l'alignement de l'(type de) variables en octets. Pour une variable x tt>: Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable's type's alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes. For a variable x:
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
Les appels à alignof tt>, offsetof tt>, et Sizeof tt> sont compilation des expressions de constante de type UIntPtr tt>. Calls to Alignof, Offsetof, and Sizeof are compile-time constant expressions of type uintptr.
Pour les types numériques a>, les formats suivants sont garantis: For the numeric types, the following sizes are guaranteed:
type taille en octets byte, uint8, int8 1 uint16, int16 2 uint32, int32, float32 4 uint64, int64, float64, complex64 8 complex128 16
Les propriétés d'alignement minimales suivantes sont garanties: The following minimal alignment properties are guaranteed:
Une structure ou type tableau a une taille de zéro si elle ne contient pas de champs (ou éléments, respectivement) qui ont une taille supérieure à zéro. Deux variables distinctes taille zéro peuvent avoir la même adresse en mémoire. A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.
Soyez le premier à commenter cet article
Tous les commentaires sont soumis à modération. Les balises HTML sont pour la plupart autorisées. Les liens contextuels et intéressants sont en follow.