5. The basic types
Go is statically typed: every value has a type, fixed when it's created, checked before your program runs. The set of built-in types is small and sharp. Here are the ones you'll use daily.
Integers
Whole numbers. The plain int is what you'll use 95% of the time — it's the
"natural" size for the machine (64 bits on modern computers). When you need a
specific size, Go has explicit widths:
- Signed:
int8,int16,int32,int64(andint) - Unsigned (non-negative only):
uint8,uint16,uint32,uint64,uint
package main
import "fmt"
func main() {
var big int = 9000000000
var small int8 = 127 // max for int8; 128 would overflow
fmt.Println(big, small)
fmt.Printf("%T %T\n", big, small)
}
Two aliases you'll meet: byte is another name for uint8 (a raw byte),
and rune is another name for int32 (a single Unicode character). More
on those when we reach strings.
Floating-point
Numbers with a fractional part. Use float64 unless you have a
specific reason not to — it's the default and the most precise.
package main
import "fmt"
func main() {
price := 19.99
half := price / 2
fmt.Printf("%.2f split in two is %.3f each\n", price, half)
}
A caution that applies to every language: floats are approximate. 0.1 + 0.2
is not exactly 0.3. Run it and see — this is normal, not a Go quirk:
package main
import "fmt"
func main() {
fmt.Println(0.1 + 0.2)
}
For money, you generally work in integer cents rather than floats to avoid this. We'll return to it.
Booleans
bool is either true or false — nothing else, and no automatic
conversion from numbers. In Go, 1 is not truthy and 0 is not falsy; a
condition must be an actual bool.
package main
import "fmt"
func main() {
isReady := true
hasErrors := 3 > 5
fmt.Println(isReady, hasErrors)
fmt.Println(isReady && !hasErrors)
}
&& is "and", || is "or", ! is "not". Comparisons (>, <, ==,
!=, >=, <=) all produce a bool.
Strings
A string is an immutable sequence of bytes, almost always holding UTF-8
text. Double quotes make a string; backticks make a raw string that
keeps newlines and ignores escapes:
package main
import "fmt"
func main() {
greeting := "Hello,\n\tGo" // \n and \t are interpreted
raw := `Hello,\n\tGo` // backticks: literally backslash-n
fmt.Println(greeting)
fmt.Println(raw)
}
Join strings with +, and get the length in bytes with len:
package main
import "fmt"
func main() {
first := "Go"
full := first + "lang"
fmt.Println(full, "has", len(full), "bytes")
}
(For non-ASCII text, byte length and character count differ — a topic for the strings lesson. For plain ASCII they're the same.)
Checking a type
When you're unsure, %T tells you exactly what you've got. Untyped literals
default to int for whole numbers and float64 for decimals:
package main
import "fmt"
func main() {
fmt.Printf("%T %T %T %T\n", 42, 3.14, true, "hi")
}
Your turn
A rectangle is width = 7 and height = 3 (both int). Print exactly:
Area: 21, Perimeter: 20
package main
import "fmt"
func main() {
width := 7
height := 3
// compute area and perimeter, then print the line
}
package main
import "fmt"
func main() {
width := 7
height := 3
area := width * height
perimeter := 2 * (width + height)
fmt.Printf("Area: %d, Perimeter: %d\n", area, perimeter)
}
Next: values that never change — constants and iota.