These are just some notes I’ve taken from The Go Programming Language by Alan A. A. Donovan & Brian W. Kernighan (which I strongly recommend if you are willing to learn Go).
These notes and code samples are mainly for self-reference. Don’t expect anything new or exciting here 🙄
Go’s types can be grouped in 4 categories:
- basic types
- aggregate types
- reference types
- interface types
This post focus on basic types.
Basic data types can be numbers, strings or booleans.
Go has 3 types of numbers: integers, floating-points and complex numbers.
Signed numbers are represented in 2’s-complement form.
The zero value for type
Go provides signed (i.e.
int64) and unsigned (i.e.
uint are the most efficient size for integers on a given platform. They have the same size, either 32 or 64 bits. Different compilers can make different choices on whether so use one or the other.
rune is a synonym for
int32 and indicates that a value is a Unicode code point. Runes are printed with verbs
a := 'a' fmt.Printf("%d %c %q\n", a) // "97 a 'a'"
byte is a synonym for
uint8. It usually contains a piece of raw data.
uintptr is an unsigned integer type used to represent pointer values. It’s size is not specified. It is generally used for low-level programming (i.e. when interoperating with C).
uintptr, and so forth, are different types and require explicit type conversion when used in a same operation:
var _1 int32 = 1 var _2 int16 = 2 var sum int sum = _1 + _2 // compile error: mismatched types int32 and int16 sum = int(_1) + int(_2) // works fine
When an overflow happens (the result of an arithmetic operation has more bits than its result type can hold), the high-order bits that do not fit are silently dropped.
Float to integer conversion discards any fractional part, truncating toward zero.
Integer literals can be also written as octal numbers if they start with
0, like in
0444, or as hexadecimal if they begin with
0X), as in
By using the
fmt package, we can control the radix and use the verbs
%x to format:
o := 0444 fmt.Printf("%d %o %#o\n", o) // "292 444 0444" x := int64(0xcafe) fmt.Printf("%d %x %#x %#X\n", x) // "51966 cafe 0xcafe 0XCAFE"
Go provides two sizes of floating-points,
float64. The limits of floating-point values can be found in the
float32 provides about 6 decimal digits of precision. A
float64 provides about 15 digits.
Use scientific notation to write very small or large numbers, with the letter
E preceding the decimal exponent:
const Avogadro = 6.02214129e23 const Planck = 6.62606957e-34
Floating-point values are usually printed with
%g verb. But it is also possible to use
%e (exponent) or
%f (no exponent) verbs.
const Avogadro = 6.02214129e23 fmt.Printf("%g %8.3f %e\n", Avogadro) // 6.02214129e+23 602214128999999968641024.000 6.022141e+23
Testing whether a specific result is equal to
math.NaN (not a number) is dangerous because comparisons with NaN always yields
Go provides two sizes of complex numbers,
complex128. The built-in function
complex creates a complex number from its real and imaginary components. The built-in
imag functions return the real and imaginary components, respectively:
var x complex128 = complex(1, 2) // 1+2i var y complex128 = complex(3, 4) // 3+4i fmt.Println(x*y) // "(-5+10i)" fmt.Println(real(x*y)) // "-5" fmt.Println(imag(x*y)) // "10"
Floating-point literals or decimal integer literals immediately followed by
i, as in
1i, denote a complex number with a zero real component.
math/cmplx package provides functions for working with complex numbers.
Two possible values:
false. The zero value for boolean types is
Use the verb
%t to print booleans:
fmt.Printf("%t", false) // "false" fmt.Printf("%t", !false) // "true"
In Go strings are immutable sequences of bytes. By convention, text strings are interpreted as UTF-8 encoded sequences of Unicode code points (runes). To know more about Unicode/UTF-8, I recommend this excelent blog post from Joel Spolsky.
A string literal is a sequence of bytes inside double quotes, such as
"hello world". The zero value for string types is the empty string
Raw string literals are represented like
`hello world`. In a raw string literal, no escape sequences are processed. Raw string literals are a generally used to write regular expressions, HTML, JSON or YAML.
len function returns the number of bytes (not runes) in a string, and the index operation
myString[i] retrieves the i-th byte of
The i-th byte of a string is not necessarily the i-th character of a string, because the UTF-8 encoding of a Unicode code point can require two or more bytes.
unicode package provides functions for working with runes, and the
unicode/utf8 package provides functions for encoding and decoding runes as bytes using UTF-8.
It is possible to specify characters in a string using Unicode escapes followed by their numeric code points (h is a hexadecimal digit):
\uhhhh for a 16-bit value
\Uhhhhhhhh for a 32-bit value
fmt.Println("\xe4\xb8\x96\xe7\x95\x8c") // 世界 fmt.Println("\u4e16\u754c") // 世界 fmt.Println("\U00004e16\U0000754c") // 世界
The substring operation
s[i:j] returns a new string based on the original one starting at index
i until the byte at index
j is not included).
j operands can be omitted.
s := "hello world" fmt.Println(s[:5]) // "hello" fmt.Println(s[7:]) // "world" fmt.Println(s[:]) // "hello, world"
+ operator makes a new string by concatenating two strings.