Basic Types And Basic Value Literals

Types can be viewed as value templates, and values can be viewed as type instances. This article will introduce the built-in basic types and their value literals in Go. Compoiste types will not get introduced in this article.

Built-in Basic Types In Go

Go supports following built-in basic types:

Each of the 17 built-in basic types belongs to one different kind of type in Go. We can use the above built-in types in code without importing any packages, though all the names of these types are non-exported identifiers.

15 of the 17 built-in basic types are numeric types. Numeric types includes integer types, floating-point types and complex types.

Go also support two built-in alias types,

The integer types whose names starting with an u are unsigned types. Values of unsigned types are always non-negative. The number in the name of a type means how many binary bits a value of the type will occpy in memory. For example, every value of the uint8 occupies 8 bits in memory. So the largest uint8 value is 255 (28-1), the largest int8 value is 127 (27-1), and the smallest int8 value is -128 (-27).

We also aften use how many bytes are occupied in memory to measure the size of a value. One byte contains 8 bits. So the size of an uint32 value is four bytes.

The sizes of int and uint values in memory are operation system dependent, either 32 or 64 bits. The size of uintptr value must be large enough to store the uninterpreted bits of a pointer value. We can learn more about pointers from the article pointers in Go later.

The real and imagine components of a complex64 value are both float32 values, and the real and imagine components of a complex128 value are both float64 values.

A boolean value represents a truth. There are only two possible boolean values in memory, they are denoted by the two predeclared built-in named constants, false and true. Name constants will be introduced in the next article.

In logic, a string value denotes a piece of text. In memory, a string value stores a sequence of bytes, which is the UTF-8 encoding representaion of the piece of text denoted by the string value. We can learn more facts on strings from the article strings in Go later.

Although there is only one built-in type for each of boolean and string types, we can define custom boolean and string types and declare alias types for the built-int boolean and string types. So there can be many boolean and string types. The same is for any kinds of numeric types. The following are some type declarations examples. In these declarations, the word type is a keyword.
// Some type definition declarations.
type status bool     // status and bool are two different types.
type MyString string // MyString and string are two different types.
type Id uint64       // Id and uint64 are two different types.
type real float32    // real and float32 are two different types.

// Some type alias declarations.
type boolean = bool // boolean and bool denote the same type.
type Text = string  // Text and string denote the same type.
type U8 = uint8     // U8, uint8 and byte denote the same type.
type char = rune    // char, rune and int32 denote the same type.

We can call the custom real type defined above and the built-in float32 type both as float32 types. Note, the second float32 word in the last sentence is a general reference, whereas the first one is a specified reference. Similarly, MyString and string are both string types, status and bool are both bool types, etc.

We can learn more on custom types in the article overview of Go type system later.

Zero Values

Each type has a zero value. The zero value of a type can be viewed as the default value of the type.

Basic Value Literals

A literal of a value is a text representation of the value in code. A value may have many literals.

The literals denoting values of basic types are called basic value literal. A basic value literal is also called a literal constant, or an unnamed constant. Named constants will be introduced in the next article.

Boolean Value Literals

Go specification doesn't define boolean literals. However, in general programming, we can view the two predeclared identifiers, false and true, as boolean literals. But we should know that the two are not literals in the strict sense.

As above has mentioned, zero values of boolean types are denoted with the predeclared false constant.

Floating-Point Value Literals

A floating-point value literal can contain an integer part, a decimal point, a fractional part, and an exponent part. Some parts can be ommited. Example:
1.23
01.23 // == 1.23
.23
1.
// A "e" or "E" starts the exponent part.
1.23e2  // == 123.0
123E2   // == 12300.0
123.E+2 // == 12300.0
1e-1    // == 0.1
.1e0    // == 0.1
0e+5    // == 0.0

The standard literals for zero value of floating-point types are 0.0, though there are many other legal literals, such as 0., .0, 0e0, etc. In fact, the zero value literals introduced in the current article for other kinds of numeric types can also represent the zero value of any floating-point type.

Imaginary Value Literals

An imaginary literal consists of a floating-point literal or decimal integer followed by the lower-case letter i. Examples:
1.23i
1.i
.23i
123i
0123i   // == 123i
1.23E2i // == 123i
1e-1i

Imaginary literals are used to represent the imaginary parts of complex values. The real and imaginary parts of a complex value must be of the same floating-point type. Here are some literals to denote complex values:
1 + 2i       // == 1.0 + 2.0i
1. - .1i     // == 1.0 + -0.1i
1.23i - 7.89 // == -7.89 + 1.23i
1.23i        // == 0.0 + 1.23i

The standard literals for zero values of complex types are 0.0+0.0i, though there are many other legal literals, such as 0i, .0i, 0+0i, etc. In fact, the zero value literals introduced in the current article for other kinds of numeric types can also represent the zero value of any complex type.

Integer Value Literals

There are three integer value literal forms, the decimal (base 10) form, the octal (base 8) form and the hex (base 16) form. For example, the following three integer literals all demote 15 in decimal.
// The following three integer literals all denote 15 in decimal.
15  // the decimal form (mustn't start with a "0")
017 // the octal form (must start with a "0")
0xF // the hex form (must start with a "0x")

The following program will print two true texts.
package main

func main() {
	println(15 == 017) // true
	println(15 == 0xF) // true
}

Note, the two == are the equal-to comparison operator, which will be introduced in common operators.

Generally, zero values of integer types are denoted as 0 in literal, though there are many other legal literals for integer zero values, such as 00 and 0x0. In fact, the zero value literals introduced in the current article for other kinds of numeric types can also represent the zero value of any integer type.

Rune Value Literals

Rune types, including custom defined rune types and the built-in rune type, are special integer types, so all rune values can be denoted by the integer literals introduced above. But rune values have one more form of literals, which is called rune literal.

A rune value is intended to store a Unicode break point. Generally, we can view a break point as a Unicode charater, but we should know that some Unicode charaters are composed of more than one break points each.

A rune literal is expressed as one or more characters enclosed in single quotes. The enclosed characters denote one Unicode break point value. There are some minor variants of the rune literal form. The most popular form of rune literals is just to enclose the charaters denoted by rune values between two single quotes. For example
'a' // an English charator
'π'
'众' // a Chinese charator
The rune literal has several variant forms. For example, the following run literals are equivalent to 'a' (the Unicode value of character "a" is 97).
'\141'   // 141 is the octal representation of decimal number 97
'\x61'   // 61 is the hex representation of decimal number 97
'\u0061'
'\U00000061'

In other words, each of the four rune literal variants will be escaped to the character a, or to a byte value 0x61.

Please note, \ must be followed be exact three octal digits, \x must be followed be exact two hex digits, \u must be followed be exact four hex digits, and \U must be followed be exact eight hex digits. Each such an octal or hex digit sequence must represent an legal Unicode code point, otherwise it fails to compile.

The following program will print 7 true texts.
package main

func main() {
	println('a' == 97)
	println('a' == '\141')
	println('a' == '\x61')
	println('a' == '\u0061')
	println('a' == '\U00000061')
	println(0x61 == '\x61')
	println('\u4f17' == '众')
}

In fact, the four variant rune literal forms just mentioned are rarely used for rune values in practice. They are occasionally used in interpreted string literals (see the next section).

In a rune literal, if a \ charater is followed by another character which is not a digital charater, x, u and U, then the two successive charaters will be escaped as one special charater. The possible charater pairs to be escaped are:
\a   (Unicode 0007) alert or bell
\b   (Unicode value 0x08) backspace
\f   (Unicode value 0x0C) form feed
\n   (Unicode value 0x0A) line feed or newline
\r   (Unicode value 0x0D) carriage return
\t   (Unicode value 0x09) horizontal tab
\v   (Unicode value 0x0b) vertical tab
\\   (Unicode value 0x5c) backslash
\'   (Unicode value 0x27) single quote

\n is the most used escape charater pair.

An example:
	println('\n') // 10
	println('\r') // 13
	println('\'') // 39

	println('\n' == 10)    // true
	println('\n' == '\x0A') // true

There are many literals which can denote the values of rune types, such as \000, \x00, \u0000, etc. In fact, we can also use any numeric literal introduced above to represent the values of rune types, such as 0, 0x0, 0.0, 0e0, 0i, etc.

String Value Literals

String values in Go are UTF-8 encoded. In fact, all Go source files must be UTF-8 encoding compatible.

There are two forms of string value literals, interpreted string literal (double quote form) and raw string literal (back quote form). For example, the following two string literals are equivalent:
// The interpreted form.
"Hello\nworld!\n\"你好世界\""

// The raw form.
`Hello
world!
"你好世界"`

In the above interpreted string literal, each \n charater pair will be escaped as one newline character, and each \" charater pair will be escaped as one double quote character. Most of such escape charater pairs are the same as the escape charater pairs used in rune literals introduced above, except that \" is only legal in interpreted string literals and \` is only legal in rune literals.

The character sequence of \, \x, \u and \U followed by several octal or hex digits introduced in the last section can also be used in interpreted string literals. Please note that, in interpreted string literals, the octal or hex values following \ and \x will be viewed as byte values instead of Unicode code points. A Unicode code point may be represented with 1-4 bytes.
// The following interpreted string literals are equivalent.
"\141\142\143"
"\x61\x62\x63"
"abc"

// The following interpreted string literals are equivalent.
"\xe4\xbc\x97\u4eba"
"\u4f17\xe4\xba\xba"
"众人"

Please note that each English character (code point) is represented with one byte, but each Chinese character (code point) is represented with three bytes.

In a raw string literal, no character sequences will be escaped. The back quote character is not allowed to appear in a raw string literal. To get better cross-platform compatibility, carriage return characters (Unicode code point 0x0D) inside raw string literals will be discarded.

Zero values of string types can be denoted as "" or `` in literal.

Representability Of Basic Value Literals

Any one string literal can represent values of any string types.

The predeclared false and true can represent values of any boolean types. But again, we should know that the two are not literals in the strict sense.

From the above section, we have learned that the zero value of a numeric type can be represented by several kinds of literals. In fact, many other values can be also represented by several kinds of literals. The following table lists some basic numeric literals and the types which values can be represented by each of these literals.

The Literal The Types Which Values The Literal Can Represent
256 All basic numeric types except the ones belong to the kinds of int8 and uint8.
255 All basic numeric types except the ones belong to the kind of int8.
-123 All basic numeric types except the unsigned ones.
123 All basic numeric types.
123.000
1.23e2
'a'
1.0+0i
1.23 All basic floating-point and complex numeric types.
0x10000000000000000
(16 zeros)
3.5e38 All basic floating-point and complex numeric types except the ones belong to the kinds of float32 and complex64.
1+2i All basic complex numeric types.
2e+308 None basic types.
Note,
  • for no values of the basic interger types provided in Go can hold 0x10000000000000000, so the literal is not representable as values of any basic interger types.
  • for the max float32 value is 3.40282346638528859811704183484516925440e+38, so 3.5e38 is not representable as values of any float32 and complex64 types.
  • for the max float64 value is 1.797693134862315708145274237317043567981e+308, so 2e+308 is not representable as values of any basic types in Go.

Each basic numeric type has a maximun and a minimum values respectively. So, so if a literal overflows the value range of a type, then the literal is not representable as values of the type.

Another note, 1.23e2 can represent values of any basic integer types, but 1.23 can't. The rule is, a literal can only be able to represent a value of an interger type without rounding and the literal doesn't overflow the value range of a type.

In the end, please note, although 0x10000000000000000 can represent values of float32 types, however it can't represent any float32 values accurately in memory. In other words, it will be rounded to the closest float32 value which can be represented accurately in memory when it is used as values of float32 types. Yes, rounding is allowed when using a literal to represent non-interger values.

Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies description flaws and code bugs.