Lexical elements: Integer literals

January 16, 2023

Integer literals

Ah integer literals! Now we’re starting to get into the meat of the language.

Go lets us express integers in four bases. 10 (decimal) is by far the most common, followed by base 16 (hexidecimal). Base 8 (octal) and base 2 (binary) are also supported, but seen fairly rarely.

Here’s how the spec describes it:

An integer literal is a sequence of digits representing an integer constant. An optional prefix sets a non-decimal base: 0b or 0B for binary, 0, 0o, or 0O for octal, and 0x or 0X for hexadecimal. A single 0 is considered a decimal zero. In hexadecimal literals, letters a through f and A through F represent values 10 through 15.

The astute reader may wonder why octal supports three prefixes, 0, 0o and 0O, whereas binary and hexidecimal each support only two (their upper- and lowercase- versions).

This is for historical reasons. Prior to the release of Go 1.13 in September 2019, there were no binary literals, and octal literals were indicated solely by the 0 prefix.

To make everything more consistent in Go 1.13, they added binary, with the respective 0b and 0B prefixes, and added the 0o and 0O prefixes for octal literals, to be consistent with the 0x and 0X prefixes already supported for hexidecimal literals.

These days, the plain 0 prefix should be considered obsolete, although it will continue to work indefinitely, if you’re using the standard gofmt tool (and you should be!), it will reformat any octal literals with the old bare 0 prefix to use 0o.

For readability, an underscore character _ may appear after a base prefix or between successive digits; such underscores do not change the literal’s value.

At the same time that Binary literals and standard Ocatl prefixes were added, they added the option to include arbitrary undescores (_) to literals. This should be used when it enhanches readability, such as to group by thousands when writing decimal literals.

int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit    = "0" | ( "1"  "9" ) [ [ "_" ] decimal_digits ] .
binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .

decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
binary_digits  = binary_digit { [ "_" ] binary_digit } .
octal_digits   = octal_digit { [ "_" ] octal_digit } .
hex_digits     = hex_digit { [ "_" ] hex_digit } .
0O600       // second character is capital letter 'O'

_42         // an identifier, not an integer literal
42_         // invalid: _ must separate successive digits
4__2        // invalid: only one _ at a time
0_xBadFace  // invalid: _ must separate successive digits

Quotes from The Go Programming Language Specification, Version of June 29, 2022

Share this

Related Content

Empty structs

We finally we have enough knowledge for the EBNF format not to seem completely foreign, so let’s jump back and take a look at that, with the examples provided in the spec… Struct types … StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName [ TypeArgs ] . Tag = string_lit . // An empty struct.

Struct tags

Struct types … A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored. struct { x, y float64 "" // an empty tag string is like an absent tag name string "any string is permitted as a tag" _ [4]byte "ceci n'est pas un champ de structure" } // A struct corresponding to a TimeStamp protocol buffer.

Struct method promotion

Yesterday we saw an example of struct field promotion. But methods (which we haven’t really discussed yet) can also be promoted. Struct types … Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows: If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.