Spécifications du langage de programmation Go

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.

Introduction
Notation
Représentation du code source
Caractères
Lettres et chiffres
Éléments lexicaux
Commentaires
Jetons
Point-virgules
Identifiants
Mots-clés
Opérateurs et délimiteurs
Entiers littéraux
Nombres littéraux à virgule flottante
Nombres imaginaires littéraux
Littéraux de type rune
Littéraux chaînes de caractères
Constantes
Types
Ensembles de méthodes
Types booléen
Types numériques
Types chaîne de caractères
Types tableau
Types slice
Types struct
Types pointeur
Types fonction
Types interface
Types map
Types chan
Caractéristiques des types et des valeurs
Identité de type
Règles d'affectation
Blocs
Déclarations et portée
Portées des étiquettes
Identifiant blank
Identifiants predeclarés
Identifiants exportés
Unicité des identificateurs
Déclarations des constantes
Iota
Déclarations des types
Déclarations des variables
Déclarations abrégées des variables
Déclarations des fonctions
Déclarations des méthodes
Expressions
Opérandes
Identifiants qualifiés
Littéraux composites
Littéraux de fonction
Expressions primaires
Sélecteurs
Expressions d'index
Expressions slice
Assertions de type
Appels
Passer des arguments à des parameters ...
Opérateurs
Priorité des opérateurs
Opérateurs arithmétiques
Integer overflow
Comparison operators
Logical operators
Address operators
Receive operator
Method expressions
Method values
Conversions
Constant expressions
Order of evaluation
Statements
Terminating statements
Empty statements
Labeled statements
Expression statements
Send statements
IncDec statements
Assignments
If statements
Switch statements
For statements
Go statements
Select statements
Return statements
Break statements
Continue statements
Goto statements
Fallthrough statements
Defer statements
Built-in functions
Close
Length and capacity
Allocation
Making slices, maps and channels
Appending to and copying slices
Deletion of map elements
Manipulating complex numbers
Handling panics
Bootstrapping
Packages
Source file organization
Package clause
Import declarations
An example package
Program initialization and execution
The zero value
Program execution
Errors
Run-time panics
System considerations
Package unsafe
Size and alignment guarantees

Introduction

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.

Notation

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.

Représentation du code source

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.

Caractères

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.

Lettres et chiffres

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" .

Éléments lexicaux

Commentaires

Il existe deux formes de commentaire :

  1. Les lignes de commentaire commencent par la séquence de caractères // et s'arrêtent à la fin de la ligne. Une ligne de commentaire est comme un retour à la ligne.
  2. Les commentaires généraux commencent par la séquence de caractères /* et continuent jusqu'à la séquence de caractères */. Un commentaire général contenant un ou plusieurs sauts de ligne est comme un retour à la ligne, sinon il est considéré comme un espace.

Les commentaires ne s'imbriquent pas.

Jetons

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.

Point-virgules

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 :

  1. 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 :

  2. Pour permettre à des instructions complexes à tenir en une seule ligne, un point-virgule peut être omis avant de fermer une paranthèse ou une accolade (")" ou "}").

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.

Identifiants

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.

Mots-clé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

Opérateurs et délimiteurs

Les séquences de caractères suivantes représentent les opérateurs, séparateurs et autres jetons spéciaux :

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
     &^          &^=

Entiers littéraux

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

Nombres littéraux à virgule flottante

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

Nombres imaginaires littéraux

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

Littéraux de type rune

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

Littéraux chaînes de caractères

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.

Constantes

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 :

  • Représenter les constantes entières avec au moins 256 bits.
  • Représenter les constantes à virgule flottante, y compris les parties d'une constante complexe, avec une mantisse d'au moins 256 bits et un exposant signé d'au moins 32 bits.
  • Produire une erreur s'il ne peut pas représenter une constante entière précisément.
  • Produire une erreur s'il ne peut pas représenter une constante à virgule flottante ou complexe en raison d'un débordement.
  • Arrondir à la constante représentable la plus proche en cas d'impossibilité de représenter une constante à virgule flottante ou complexe en raison des limites sur la précision.

Ces exigences s'appliquent à la fois aux constantes littérales et au résultat de l'évaluation des expressions constantes.

Types

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 compositesarray, 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.

Ensembles de méthodes

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.

Types booléen

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.

Types numériques

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.

Types chaîne de caractères

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.

Types tableau

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))

Types slice

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.

Types struct

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 :

  • Si S contient un champ anonyme T, l'ensemble de méthodes de S et *S incluent des méthodes promues avec le récepteur T. L'ensemble de méthodes de *S inclut également des méthodes promues avec le récepteur *T.
  • Si S contient un champ anonyme *T, les ensembles de méthodes de S et *S incluent des méthodes promues avec le récepteur T ou *T.

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"
}

Types pointeur

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

Types fonction

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)

Types interface

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
}

Types map

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é.

Types chan

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é.

Caractéristiques des types et des valeurs

Identité de type

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 :

  • Deux types de tableaux sont identiques s'ils ont des types d'éléments identiques et la même longueur (de tableau).
  • Deux types de slice sont identiques s'ils ont des types d'éléments identiques.
  • Deux types de structure sont identiques si elles ont la même séquence de champs ainsi que si les champs correspondants ont les mêmes noms, les mêmes types et des étiquettes identiques.
    Deux champs anonymes sont considérés comme ayant le même nom. Les noms de champ en minuscule de paquets différents sont toujours différents.
  • Deux types de pointeurs sont identiques s'ils ont des types de base identiques.
  • Deux types de fonctions sont identiques s'ils ont le même nombre de paramètres et de valeurs de résultat, le types des paramètres correspondants et les types des résultats sont identiques, et si, soit les deux fonctions sont variadiques ou aucune de l'est. Les noms de paramètres et de résultats ne sont pas tenus de correspondre.
  • Deux types interface sont identiques s'ils ont le même ensemble de méthodes avec les mêmes noms et des types de fonctions identiques. Les noms de méthode en minuscule de paquets différents sont toujours différents. L'ordre des méthodes n'est pas pris en compte.
  • Deux types de map sont identiques s'ils ont des types de clés et de valeurs identiques.
  • Deux types de canaux sont identiques s'ils ont des types de valeurs identiques et la même direction.

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.

Règles d'affectation

Une valeur x est assignable à une variable de type Tx est assignable à T ») dans n'importe lequel de ces cas :

  • Le type de x est identique à T.
  • Le type de xV et T ont des types sous-jacents identiques et au moins un des deux entre V et T n'est pas un type nommé.
  • T est un type interface et ximplémenteT.
  • x est une valeur de canal bidirectionnel, T est un type de canal, le type de xV et T ont des types d'éléments identiques et au moins un des deux entre V et T n'est pas un type nommé.
  • x est l'identifiant prédéclaré nil et T est un pointeur, une fonction, une slice, une map, un canal ou un type interface.
  • x est une constante non typée representable par une valeur de type T.

Blocs

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 :

  1. Le bloc univers comprend tout le texte source Go.
  2. Chaque paquet a un bloc de paquet contenant tout le texte source Go de ce package.
  3. Chaque fichier possède un bloc de fichier contenant tout le texte source Go de ce fichier.
  4. Chaque instruction if, for, et switch est considérée comme étant dans son propre bloc implicite.
  5. Chaque clause dans une instruction switch ou select agit comme un bloc implicite.

Les blocs s'imbriquent et l'influencent la portée.

Déclarations et 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 :

  1. La portée d'un identifiant predeclaré est le bloc univers.
  2. La portée d'un identifiant désignant une constante, un type, une variable ou une fonction (mais pas une méthode) déclarée au plus haut niveau (en dehors de toute fonction) est le bloc de paquet.
  3. La portée du nom de paquet d'un paquet importé est le bloc de fichier du fichier contenant la déclaration d'importation.
  4. La portée d'un identifiant désignant un récepteur de méthode, un paramètre de fonction, ou une variable de résultat est le corps de la fonction.
  5. La portée d'un identifiant de constante ou de variable déclarée dans une fonction commence à la fin de la ConstSpec ou VarSpec (ShortVarDecl pour de courtes déclarations de variables) et se termine à la fin du bloc conteneur le plus interne.
  6. La portée d'un identifiant de type déclaré dans une fonction commence à l'identifiant dans le TypeSpec et se termine à la fin du bloc conteneur le plus interne.

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.

Portées des étiquettes

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.

Identifiant blank

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.

Identifiants predeclarés

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

Identifiants exportés

Un identifiant peut être exporté pour permettre l'accès à partir d'un autre paquet. Un identifiant est exportée à ces deux conditions :

  1. le premier caractère du nom de l'identifiant est une lettre majuscule Unicode (classe Unicode « Lu »), et
  2. l'identifiant est déclaré dans le bloc de paquet ou il s'agit d'un nom de champ ou d'un nom de méthode.

Tous les autres identifiants ne sont pas exportés.

Unicité des identificateurs

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.

Déclarations des constantes

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
)

Iota

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.

Déclarations des types

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)
}

Déclarations des variables

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.

Déclarations abrégées des variables

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.

Déclarations des fonctions

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

Déclarations des méthodes

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 *TT 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.

Expressions

Une expression spécifie le calcul d'une valeur en appliquant des opérateurs et des fonctions aux opérandes.

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.

Identifiants qualifiés

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

Littéraux composites

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:

  • Une clé doit être un nom de champ déclaré dans le LiteralType.
  • Une liste des éléments qui ne contient pas toutes les clés doit lister un élément pour chaque champ de structure dans l'ordre dans lequel les champs sont déclarées.
  • Si un élément possède une clé, chaque élément doit avoir une clé.
  • Une liste d'éléments qui contient des clés n'a pas besoin d'avoir un élément pour chaque champ de structure. Les champs omis obtenient la valeur zéro pour ce champ.
  • Un littéral peut omettre la liste des éléments, un tel littéral s'évalue à la valeur zéro pour son type.
  • C'est une erreur de spécifier un élément pour un champ non exporté d'une structure appartenant à un paquet différent.

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 :

  • Chaque élément a un indice entier qui lui est associé et qui marque sa position dans le tableau.
  • Un élément avec une clé utilise la clé comme son indice ; la clé doit être une expression de constante entière.
  • Un élément sans clé utilise l'index de l'élément précédent plus un. Si le premier élément n'a pas de clé, son indice est égal à zéro.

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,
}

Littéraux de fonction

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.

Expressions primaires

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()

Sélecteurs

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 :

  1. Pour une valeur x de type T ou *TT n'est pas un type interface, x.f désigne le champ ou la méthode à la plus faible profondeur dans T où il y a un tel objet f. S'il n'y a pas exactement un f de faible profondeur, l'expression de sélection est illégale.
  2. Pour une variable x de Type II est un type interface, x.f désigne la méthode réelle avec le nom f de la valeur attribuée à x. S'il n'y a pas de méthode avec le nom f dans l'ensemble des méthodes de I, l'expression de sélection est illégale.
  3. Dans tous les autres cas, l'expression x.f est illégale.
  4. Si x est de type pointeur et a la valeur nil et que x.f désigne un champ de structure, l'évaluation ou l'affectation à x.f provoque une panique lors de l'exécution.
  5. Si x est de type interface et a la valeur nil, appeler ou évaluer la méthode x.f provoque une panique lors de l'exécution.

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 *AA 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()

Expressions d'index

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 :

  • l'indice x doit être de type entier ou non typé, il est dans les limites si 0 <= x < len(a), sinon il est hors limites.
  • un index constant doit être non négatif et représentable par une valeur de type int.

Pour a de type arrayA :

  • un index constant doit être dans les limites.
  • si x est hors limites au moment de l'exécution, une panique d'exécution se produit.
  • a[x] est l'élément de tableau à l'index x et le type de a[x] est le type de l'élément A.

Pour a, un pointeur vers un type array :

  • a[x] est un raccourci pour (*a)[x]

Pour a de type sliceS :

  • si x est hors limites au moment de l'exécution, une panique d'exécution se produit.
  • a[x] est l'élément de slice à l'index x et le type de a[x] est le type de l'élément de S.

Pour a de type chaîne :

  • un index constant doit être dans les limites si la chaîne a est aussi une constante.
  • si x est hors limites au moment de l'exécution, une panique d'exécution se produit.
  • a[x] est la valeur de l'octet non constant à l'index x et le type de a[x] est byte.
  • On ne peut pas affecter une valeur à a[x].

Pour a de type mapM :

  • le type de x doit être assignable avec le type de clé de M.
  • si la map contient une entrée avec la clé x, a[x] est la valeur de la map à la clé x et le type de a[x] est le type de valeur de M.
  • si la map est égale à nil ou ne contient pas une telle entrée, a[x] est la valeur zéro pour le type de valeur de M.

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.

Expressions slice

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é.

Expressions slice simples

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.

Expressions slice complètes

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.

Assertions de type

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)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.

Appels

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.

Passer des arguments à des parameters ...

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.

Opérateurs

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 

Priorité des opérateurs

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

Opérateurs arithmétiques

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.

Débordement des entiers

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

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 :

  • Les valeurs booléennes sont comparables. Deux valeurs booléennes sont égales si elles sont soit toutes les deux true ou toutes les deux false.
  • Les valeurs entières sont comparables et ordonnées, de la manière habituelle.
  • Les valeurs à virgule flottante sont comparables et ordonnées, tel que défini par la norme IEEE-754.
  • Les valeurs complexes sont comparables. Deux valeurs complexes u et v sont égales si real(u) == real(v) et imag(u) == imag(v).
  • Les valeurs de chaîne de caractères sont comparables et ordonnées, lexicalement octet par octet.
  • Les valeurs de pointeur sont comparables. Deux valeurs de pointeurs sont égales si elles pointent vers la même variable ou si les deux ont une valeur nil. Les pointeurs vers des variables de taille zéro distinctes peuvent ou ne peuvent pas être égales.
  • Les valeurs de type canal sont comparables. Deux valeurs de type canal sont égales si elles ont été créées par le même appel à make ou si les deux ont une valeur nil.
  • Les valeurs interface sont comparables. Deux valeurs interface sont égales si elles ont des types dynamiques identiques et des valeurs dynamiques égales ou si les deux ont une valeur nil.
  • Une valeur x de type X qui n'est pas un type interface et une valeur t de type interface T sont comparables lorsque les valeurs de type X sont comparables et X implémente T. Elles sont égales si le type dynamique det est identique à X et que la valeur dynamique de t est égale à x.
  • Les valeurs de type structure sont comparables si leurs champs sont comparables. Deux valeurs de type structure sont égales si leurs champs correspondants (non blank) sont égaux.
  • Les valeurs d'un tableau sont comparables si les valeurs du type d'élément de tableau sont comparables. Deux valeurs de tableau sont égales si leurs éléments correspondants sont égaux.

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
)

Opérateurs logiques

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"

Opérateurs d'adresses

Pour un opérande x de Type T , l'opération d'adresse et x génère un pointeur de type * T x . L'opérande doit être adressable , 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 peut également être un (éventuellement entre parenthèses) littérale composite. Si l'évaluation de x causerait une panique panique d'exécution, puis l'évaluation de et x 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 , pointeur d'indirection * x désigne la valeur de type T a à par x . Si x est nil, une tentative pour évaluer * x 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

Opérateur de réception

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.

Expressions méthode

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.

Valeurs de méthode

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 , 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 est équivalent à (& t). Mp . 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)

Conversions

Les conversions sont des expressions de la forme T (x) T est un type et x est une expression qui peut être converti en un type T . 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 * ou <- , ou si le type commence par le mot-clé fonction 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 valeur x peut être converti en type T dans aucun de ces cas: A constant value x can be converted to type T in any of these cases:

  • x est représentable par une valeur de type T . x is representable by a value of type T.
  • x est une constante à virgule flottante, T est un type à virgule flottante, et x est représentable par une valeur de type T après avoir contourné en utilisant IEEE 754 règles rondes à même. Le constante T (x) est la valeur arrondie. x is a floating-point constant, T is a floating-point type, and x is representable by a value of type T after rounding using IEEE 754 round-to-even rules. The constant T(x) is the rounded value.
  • x est une constante entière et T est un type de chaîne . Le même règle comme pour les non-constante x s'applique dans ce cas. x is an integer constant and T is a string type. The same rule as for non-constant x applies in this case.

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 peut être converti en un type T dans aucun de ces cas: A non-constant value x can be converted to type T in any of these cases:

  • x est assignable pour T . x is assignable to T.
  • x type et T ont types qui sous-tend l '. x's type and T have identical underlying types.
  • x type et T s ' sont des types de pointeurs anonymes et leurs types de base de pointeur avoir des types sous-jacents identiques. x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
  • x type et T Types deux entiers ou à virgule flottante sont l '. x's type and T are both integer or floating point types.
  • x type et T 's sont tous les deux des types complexes. x's type and T are both complex types.
  • x est un nombre entier ou une tranche d'octets ou de runes et T est un type de chaîne. x is an integer or a slice of bytes or runes and T is a string type.
  • x est une chaîne et T est une tranche d'octets ou de runes. x is a string and T is a slice of bytes or runes.

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 et encourir un coût d'exécution. Tous les autres conversions ne changent le type mais pas la représentation x . 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 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.

Conversions entre types numériques

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:

  1. Lors de la conversion entre types d'entiers, si la valeur est un entier signé, il est étendu à signer implicite précision infinie, sinon elle est nulle prolongée. Il est alors tronqué pour s'adapter à la taille du type de résultat. Par exemple, si v: = uint16 (0x10F0) , puis uint32 (int8 (v)) == 0xFFFFFFF0 . La conversion donne toujours une valeur valide, il n'y a aucune indication de débordement. When converting between integer types, if the value is a signed integer, it is sign extended to implicit infinite precision; otherwise it is zero extended. It is then truncated to fit in the result type's size. For example, if v := uint16(0x10F0), then uint32(int8(v)) == 0xFFFFFFF0. The conversion always yields a valid value; there is no indication of overflow.
  2. Lors de la conversion d'un nombre à virgule flottante à un nombre entier, la fraction est rejetée (troncature vers zéro). When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero).
  3. Lors de la conversion d'un nombre entier ou nombre à virgule flottante à un type à virgule flottante, ou un nombre complexe à un autre type complexe, la valeur du résultat est arrondi à la précision spécifiée par le type de destination. Par exemple, la valeur d'une variable x de Type float32 peut être stockée à l'aide de précision supplémentaire au-delà d'un nombre IEEE-754 32 bits, mais float32 (x) représente la raison de l'arrondissement x de valeur à la précision 32-bit. De même, x + 0,1 peut utiliser plus de 32 bits de précision, mais float32 (x + 0,1) ne fonctionne pas. When converting an integer or floating-point number to a floating-point type, or a complex number to another complex type, the result value is rounded to the precision specified by the destination type. For instance, the value of a variable x of type float32 may be stored using additional precision beyond that of an IEEE-754 32-bit number, but float32(x) represents the result of rounding x's value to 32-bit precision. Similarly, x + 0.1 may use more than 32 bits of precision, but float32(x + 0.1) does not.

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.

Conversions vers et à partir d'un type chaîne de caractères

  1. Conversion d'un entier signé ou non signé à un type de chaîne donne une chaîne contenant la représentation UTF-8 de l'entier. Les valeurs hors plage de points de code Unicode valides sont convertis en "\ uFFFD" . Converting a signed or unsigned integer value to a string type yields a string containing the UTF-8 representation of the integer. Values outside the range of valid Unicode code points are converted to "\uFFFD".
    string('a')       // "a"
    string(-1)        // "\ufffd" == "\xef\xbf\xbd"
    string(0xf8)      // "\u00f8" == "ø" == "\xc3\xb8"
    type MyString string
    MyString(0x65e5)  // "\u65e5" == "?" == "\xe6\x97\xa5"
    
  2. Conversion d'une tranche d'octets à un type de chaîne donne une chaîne dont octets successifs sont les éléments de la tranche. Converting a slice of bytes to a string type yields a string whose successive bytes are the elements of the slice.
    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ø"
    
  3. Conversion d'une tranche de runes à un type de chaîne donne une chaîne qui est la concaténation des valeurs de runes individuelles converties en chaînes. Converting a slice of runes to a string type yields a string that is the concatenation of the individual rune values converted to strings.
    string([]rune{0x767d, 0x9d6c, 0x7fd4})   // "\u767d\u9d6c\u7fd4" == "???"
    string([]rune{})                         // ""
    string([]rune(nil))                      // ""
    
    type MyRunes []rune
    string(MyRunes{0x767d, 0x9d6c, 0x7fd4})  // "\u767d\u9d6c\u7fd4" == "???"
    
  4. Conversion d'une valeur d'un type de chaîne à une tranche de type octets donne une tranche dont les éléments successifs sont les octets de la chaîne. Converting a value of a string type to a slice of bytes type yields a slice whose successive elements are the bytes of the string.
    []byte("hellø")   // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    []byte("")        // []byte{}
    
    MyBytes("hellø")  // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    
  5. Conversion d'une valeur d'un type de chaîne à une tranche de type runes donne une tranche contenant les points de code Unicode individuels de la chaîne. Converting a value of a string type to a slice of runes type yields a slice containing the individual Unicode code points of the string.
    []rune(MyString("???"))  // []rune{0x767d, 0x9d6c, 0x7fd4}
    []rune("")                 // []rune{}
    
    MyRunes("???")           // []rune{0x767d, 0x9d6c, 0x7fd4}
    

Expressions constantes

Les expressions constantes ne peuvent contenir que constante 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 donne toujours une constante booléenne non typée. Si l'opérande gauche d'un passer expression 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 . 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 à 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 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 ^ 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.

Ordre d'évaluation

Lors de l'évaluation de la opérandes d'une expression, affectation , déclaration de retour , 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 () , h () , i () , j () , <-c , g () , et k () . Cependant, l'ordre de ces événements par rapport à l'évaluation et à l'indexation de x et l'évaluation de y 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) le plus y + z est effectuée avant d'ajouter x . 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.

Instructions

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 .

Instructions de terminaison

Une instruction de terminaison est l'une des instructions suivantes:

  1. Une instruction "return" ou "goto" statement.
    • Un appel à la fonction intégrée panic.
      • Un bloc dans lequel la liste d'instructions se termine par une instruction de terminaison.
        • An "if" statement in which:
          • the "else" branch is present, and
          • both branches are terminating statements.
        • A "for" statement in which:
          • there are no "break" statements referring to the "for" statement, and
          • the loop condition is absent.
        • A "switch" statement in which:
          • there are no "break" statements referring to the "switch" statement,
          • there is a default case, and
          • the statement lists in each case, including the default, end in a terminating statement, or a possibly labeled "fallthrough" statement.
        • A "select" statement in which:
          • there are no "break" statements referring to the "select" statement, and
          • the statement lists in each case, including the default if present, end in a terminating statement.
        • A labeled statement labeling a terminating statement.

        Toutes les autres déclarations ne sont pas abolis. All other statements are not terminating.

        Une liste 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.

        Empty statements

        La déclaration vide ne fait rien. The empty statement does nothing.

        EmptyStmt = .
        

        Labeled statements

        Une déclaration marqué peut être la cible d'un goto , briser ou continuer 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")
        

        Expression statements

        À l'exception des fonctions intégrées spécifiques, la fonction et la méthode appelle et opérations de réception 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
        

        Send statements

        Une déclaration d'envoi envoie une valeur sur un canal. L'expression des chaînes doit être de type de canal , la direction du canal doit permettre les opérations d'envoi, et le type de la valeur à envoyer doit être cessible 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 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 et len 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
        

        IncDec statements

        Le "+ +" et "-" états augmentent ou diminuent leurs opérandes par le non typé constante 1 . Comme une mission, l'opérande doit être adressable 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
        

        Assignments

        Assignment = ExpressionList assign_op ExpressionList .
        
        assign_op = [ add_op | mul_op ] "=" .
        

        Chaque opérande côté gauche doit être adressable , une expression carte d'index, ou (pour = Missions seulement) le identifiant blanc . 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 x op = y op est une opération arithmétique binaire équivalent à x = x op y mais évalue x une seule fois. L'op = 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 ou carte fonctionnement ou une affirmation de type . Le nombre d'opérandes sur le côté gauche, doit correspondre au nombre de valeurs. Par exemple, si f 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 et la seconde à y . 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 e expression de droite est affectée à la n 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 et pointeur indirections (y compris les indirections pointeur implicites dans sélecteurs ) 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 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:

        1. Si un constante est affecté à une variable de type ou l'identifiant vierge interface, la constante est le premier converti pour saisir bool , rune , int , float64 , complex128 ou chaîne , 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.

        2. Si un côté gauche est l'identificateur vide, tout dactylographiée ou valeur non constante, sauf pour l'identificateur prédéclaré nil 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.

        If statements

        "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
        }
        

        Switch statements

        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.

        Expression switches

        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 . 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 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()
        }
        

        Type switches

        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 en utilisant le mot réservé tapez 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 contre le type dynamique de l'expression x . Comme avec les assertions de type, x doit être type d'interface , et chaque type non interface T figurant dans un cas doivent mettre en œuvre le type de x . 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 . Lorsque cette forme est utilisée, la variable est déclarée au début du bloc implicite 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, 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 de l'interface de type {} , 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.

        Instructions for

        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 . 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 et un poste de déclaration, comme une cession, une augmentation ou diminution déclaration. La déclaration d'initialisation peut être une courte déclaration de variable , 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 sont requis, sauf si il ya seulement une condition. Si l'état est absent, il est équivalent à true . 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 à des variables d'itération 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 , qui peut être un tableau, pointeur vers un tableau, tranche, ficelle, carte, ou canal permettant opérations de réception . Comme une cession, les opérandes de gauche doivent être adressable 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 , 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 , 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
        
        1. Pour un tableau, pointeur sur un tableau, ou la valeur de la tranche un , l'indice d'itération valeurs sont produites dans l'ordre croissant, en commençant à l'index de l'élément 0. Si seule la première variable d'itération est présent, la boucle de gamme produit des valeurs d'itération de 0 à len (a) -1 et n'indexe pas dans le tableau ou une tranche lui-même. Pour une nil tranche, le nombre d'itérations est 0. For an array, pointer to array, or slice value a, the index iteration values are produced in increasing order, starting at element index 0. If only the first iteration variable is present, the range loop produces iteration values from 0 up to len(a)-1 and does not index into the array or slice itself. For a nil slice, the number of iterations is 0.
        2. Pour une valeur de chaîne, les "range" itération de la clause sur les points de code Unicode dans la chaîne à partir de l'index de l'octet 0. Sur itérations successives, la valeur de l'indice sera l'indice du premier octet de points de code UTF-8 codés successifs dans la chaîne, et la seconde valeur, de type rune , sera la valeur de la point de code correspondant. Si l'itération rencontre une séquence UTF-8 valide, la deuxième valeur sera 0xFFFD , le caractère de remplacement Unicode, et la prochaine itération avancera un seul octet dans la chaîne. For a string value, the "range" clause iterates over the Unicode code points in the string starting at byte index 0. On successive iterations, the index value will be the index of the first byte of successive UTF-8-encoded code points in the string, and the second value, of type rune, will be the value of the corresponding code point. If the iteration encounters an invalid UTF-8 sequence, the second value will be 0xFFFD, the Unicode replacement character, and the next iteration will advance a single byte in the string.
        3. L'ordre d'itération sur les cartes n'est pas spécifié et n'est pas assuré d'être le même d'une itération à l'autre. Si la carte entrées qui n'ont pas encore été atteints sont éliminés lors de l'itération, les valeurs d'itération correspondants ne seront pas produites. Si la carte des entrées sont créées lors de l'itération, cette entrée peut être produite lors de l'itération ou peut être ignoré. Le choix peut varier pour chaque entrée créée et d'une itération à la suivante. Si la carte est nil, le nombre d'itérations est 0. The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If map entries that have not yet been reached are removed during iteration, the corresponding iteration values will not be produced. If map entries are created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
        4. Pour les canaux, les valeurs d'itération produites sont des valeurs successives envoyées sur le canal jusqu'à ce que le canal est fermé . Si le canal est nil, la gamme de blocs d'expression toujours. For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

        Les valeurs d'itération sont affectées aux variables d'itération respectifs comme dans un instruction d'affectation . 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 (: = ). Dans ce cas, leurs types sont définis pour les types des valeurs d'itération respectives et leur champ 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)
        }
        

        instructions Go

        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 , 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 . 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 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)
        

        instruction select

        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 . 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 , 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 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 . 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
        

        Instructions de terminaison

        Un "return" dans une fonction F termine l'exécution de F , et éventuellement fournit une ou plusieurs valeurs de résultats. Toute fonctions différé par F sont exécutés avant F 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:

        1. La ou les valeurs de retour peuvent être mentionnés explicitement dans la déclaration "de retour". Chaque expression doit être une valeur unique et assignable à l'élément correspondant de type de résultat de la fonction. The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
          func simpleF() int {
          	return 2
          }
          
          func complexF1() (re float64, im float64) {
          	return -7.0, -4.0
          }
          
        2. La liste d'expression dans la déclaration "de retour" peut être un seul appel à une fonction à valeurs multiples. L'effet est comme si chaque valeur retournée par cette fonction a été attribuée à une variable temporaire avec le type de la valeur respective, suivie d'une déclaration "retourner" la liste de ces variables, à laquelle pointent les règles de l'affaire précédente s'applique. The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
          func complexF2() (re float64, im float64) {
          	return complexF1()
          }
          
        3. La liste d'expression peut être vide si le type de résultat de la fonction précise des noms pour ses résultats paramètres . Les paramètres de résultat agissent comme des variables locales ordinaires et la fonction peuvent leur affecter des valeurs comme nécessaire. La déclaration "de retour" renvoie les valeurs de ces variables. The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
          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 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.

        Break statements

        Un "break" déclaration met fin à l'exécution de la "pour" , "switch" , ou ", sélectionnez " 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
        			}
        		}
        	}
        

        Continue statements

        Un "continuer" déclaration commence la prochaine itération de la boucle "for" à 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)
        		}
        	}
        

        Goto statements

        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 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 saute la création de v . is erroneous because the jump to label L skips the creation of v.

        Un "goto" déclaration extérieur d'un bloc 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 est à l'intérieur du «pour» le bloc de déclaration, mais le goto est pas. is erroneous because the label L1 is inside the "for" statement's block but the goto is not.

        Fallthrough statements

        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 . 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" .
        

        Defer statements

        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 atteint la fin de sa corps de la fonction , ou parce que le goroutine correspondant est paniquer . 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 . 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 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 et la fonction environnante est paramètres de résultat nommée 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 .) 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
        }
        

        Fonctions intégrées

        Les fonctions intégrées sont prédéclaré . 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 , 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 .
        

        Close

        Pour un canal c , la clôture de la fonction intégrée (c) documents qui ne seront plus les valeurs envoyés sur le canal. C'est une erreur si c 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 . Après l'appel près , 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 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.

        Longueur et capacité

        Les fonctions intégrées len et cap prennent des arguments de différents types et renvoient un résultat de type int . La mise en œuvre garantit que le résultat va toujours dans un int . 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) est constante si s est une chaîne constante. Les expressions len (s) et bouchon (s) sont des constantes si le type de s est un tableau ou un pointeur vers un tableau et l'expression s ne contient pas canal reçoit ou la fonction appelle , dans ce cas s n'est pas évalué. Sinon, les appels de len et cap ne sont pas constants et s 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.

        Allocation

        La fonction intégrée nouveau prend un type T et retourne une valeur de type * T . La mémoire est initialisée comme décrit dans la section sur valeurs initiales . 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 , initialise ( a = 0, b = 0,0 ), et renvoie une valeur de type * S 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.

        Making slices, maps and channels

        La fonction intégrée faire prend un type T , 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 (pas * T ). La mémoire est initialisée comme décrit dans la section sur valeurs initiales . 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 et m 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 . Si les deux n et m sont fournies et sont constants, alors n doit pas être supérieure à m . Si n est négatif ou plus grand que m 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
        

        Appending to and copying slices

        Les fonctions intégrées append et copie 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 fonction append ajoute zéro ou plusieurs valeurs x pour s de Type S , qui doit être un type de tranche, et renvoie la tranche obtenue, également de type S . Les valeurs x sont passés à un paramètre de type ... T T est le type d'élément de S et règles de passage de paramètres s'applique. Comme un cas particulier, append accepte aussi un premier argument assignable à taper [] octet avec un second argument de type chaîne de caractères suivie par ... . 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 n'est pas assez grand pour accueillir les valeurs supplémentaires, append 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 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 éléments copies de tranche d'une source src pour une destination dst et renvoie le nombre d'éléments copiés. Les deux arguments doivent avoir identique type d'élément T et doit être assignable pour une tranche de Type [] T . Le nombre d'éléments copiés est le minimum de len (src) et len (dst) . Comme un cas particulier, copie accepte aussi un argument de destination assignable à taper [] octet 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")
        

        Deletion of map elements

        La fonction intégrée supprimer supprime l'élément avec la clé k à partir d'une carte m . Le type de k doit être assignable pour le type de clé de m . 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 est nil ou l'élément m [k] n'existe pas, supprimer est un non-op. If the map m is nil or the element m[k] does not exist, delete is a no-op.

        Manipulating complex numbers

        Trois fonctions monter et démonter des nombres complexes. La fonction intégrée complexe construit une valeur complexe d'une partie à virgule flottante réel et l'imaginaire, tout réel et imag 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 , 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 pour float32 , complex128 pour float64 . La vraie et imag fonctions forment ensemble l'inverse, si pour une valeur complexe z , z = = complexe (réel (z), imag (z)) . 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
        

        Gérer les paniques d'exécution

        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 , un appel explicite à panic ou une panique d'exécution termine l'exécution de F . Toute fonctions différé par F sont alors exécuté comme d'habitude. Ensuite, toutes les fonctions différés gérés par 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 . Cette séquence de terminaison est appelé paniquer . 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 permet un programme pour gérer le comportement d'un goroutine de panique. Supposons une fonction G reporte une fonction D qui appelle récupérer et la panique se produit dans une fonction sur le même goroutine dans lequel G est l'exécution. Lorsque le déroulement des fonctions différés atteint D , la valeur de retour de D de l 'appel à récupérer sera la valeur passée à l'appel de panique . Si D retourne normalement, sans lancer une nouvelle panique , la séquence s'arrête à paniquer. Dans ce cas, l'état de fonctions appelées entre G et l'appel à panique est rejeté, et l'exécution normale reprend. Toutes les fonctions reportées par G avant D sont ensuite exécutés et G 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:

        • l'argument de panic était nil;
        • la goroutine ne panique pas;
        • recover n'a pas été appelée directement par une fonction différée.

        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()
        }
        

        Amorçage

        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
        

        Paquets

        Aller programmes sont construits en reliant paquets . 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é 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.

        Organisation des fichiers sources

        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 ";" } .
        

        Clause de paquet

        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.

        Déclarations d'importation

        Une déclaration d'importation indique que le fichier source contenant la déclaration dépend de la fonctionnalité de la importée paquet ( initialisation et l'exécution ) et permet d'accéder à Exported_identifiers exportés 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 à 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 . 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 (. ) apparaît à la place d'un nom, tous les identificateurs exportés de l'emballage déclarés dans paquet bloc de ce paquet 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 "# $% & '() *,:;? <=> [\] ^` {|} 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 , qui exporte la fonction Sin , et installé le paquet compilé dans le fichier identifié par "lib / math" . Ce tableau illustre comment Sin 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 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"
        

        Un exemple de paquet

        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()
        }
        

        Initialisation et exécution du programme

        La valeur zéro

        Lorsque la mémoire est allouée pour stocker une valeur, soit par une déclaration ou un appel de faire ou nouveau , 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 pour son type: false pour les booléens, 0 pour les entiers, 0.0 pour les flotteurs, "" 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
        

        L'exécution du programme

        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 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 dépend B , A sera fixé après B . 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 dépend B si la valeur de A contient une mention de B , contient une valeur dont initialisation mentionne B , ou mentionne une fonction qui mentionne B , 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 de l 'initialisation appelle une fonction définie dans un autre package qui fait référence à B . 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 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 , P 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 avec tous les paquets qu'elle importe, transitive. Le paquet principal doit avoir le nom de paquet principale et déclarer une fonction principale 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 . Lorsque la fonction principales rendement, le programme se termine. Il n'attend pas pour d'autres (non- principale ) 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 fonctions-qui se passe dans un seul goroutine, séquentiellement, un paquet à la fois. Un 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 fonctions: il ne démarre pas la prochaine initialisation 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.

        Erreurs

        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)
        

        Panique d'exécution

        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 équivalent à un appel de la panique de la fonction intégrée avec une valeur du type défini par l'implémentation d'interface runtime.Error . Ce type satisfait l'erreur du prédéclaré type d'interface . 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
        }
        

        Considérations système

        Paquet unsafe

        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 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 UIntPtr peuvent être convertis en un Pointer type et vice versa. Un Pointer est un type pointeur , mais un pointeur valeur ne peuvent pas être déréférencé . 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 et Sizeof prennent une expression x de tout type et de retour de l'alignement ou la taille, respectivement, d'un hypothétique variables v comme si v a été déclarée par var v = x . 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 prend une (éventuellement entre parenthèses) sélecteur sf , désignant un champ f de la structure désignée par s ou * s , et renvoie le champ de décalage en octets par rapport à l'adresse de la structure. Si f est un de domaine intégré , il doit être accessible sans indirections pointeur à travers les champs de la structure. Pour une structure s avec le champ f : 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é , c'est pour les adresses d'une variable à un multiple d'un facteur, l'alignement le type de la variable . La fonction alignof 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 : 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 , offsetof , et Sizeof sont compilation des expressions de constante de type UIntPtr . Calls to Alignof, Offsetof, and Sizeof are compile-time constant expressions of type uintptr.

        Garanties de taille et d'alignement

        Pour les types numériques , 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:

        1. Pour une variable x de tout type: unsafe.Alignof (x) est au moins 1. For a variable x of any type: unsafe.Alignof(x) is at least 1.
        2. Pour une variable x de type struct: unsafe.Alignof (x) est la plus grande de toutes les valeurs unsafe.Alignof (xf) pour chaque domaine f de x , mais au moins 1. For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.
        3. Pour une variable x de type tableau: unsafe.Alignof (x) est le même que unsafe.Alignof (x [0]) , mais au moins une. For a variable x of array type: unsafe.Alignof(x) is the same as unsafe.Alignof(x[0]), but at least 1.

        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.


        Étiquettes :   specification 
        Portrait de Benjamin BALET
        Benjamin BALET
        Consultant APM

        Retrouvez mes cooordonées

        Benjamin BALET sur viadeo






        Vous aimerez aussi

        Commentaires

        Soyez le premier à commenter cet article

        Publier un commentaires

        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.

        (requis)
        (requis)
        (requis, mais non publié)
        (recommandé si vous souhaitez être publié)