Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Go  Module 2 – Basics: values, types and control flow

Basic types: numbers, strings, bools, conversion

Go's number types and their ranges, explicit conversions and strconv, strings as bytes and plain bools, then overflow, division and money in whole cents.

  • Beginner
  • 15 minutes
  • Examples run with Go 1.27.1 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 5 of 15 minutes free
Free: Each number type has a fixed size and range · Go converts only where you write a conversion · A string holds bytes, and a bool holds only true or false. With a pass: 2 in-depth parts and 3 interview answers, about 10 minutes.

What you will learn

  • Choose between int, int64, uint8, float64 and the other number types
  • Convert between number types, and between numbers and strings, with conversions and strconv
  • Predict integer overflow, division and remainder results
  • Represent money in whole cents without floating-point errors

Before you start

What you’ll learn · Before you start

What you will learn

  • Choose between int, int64, uint8, float64 and the other number types
  • Convert between number types, and between numbers and strings, with conversions and strconv
  • Predict integer overflow, division and remainder results
  • Represent money in whole cents without floating-point errors

Before you start

On this page

Go has fifteen number types, and it never converts between them on its own: adding an int to an int64 does not compile, even where both are 64 bits wide. The strictness is deliberate, because the type of a number decides how big it can get, whether it keeps a fraction, and what happens when a result does not fit.

You will choose a type for each kind of number, convert between types and to and from text, and see why the length of a string counts bytes and why no number can stand in for a bool.

Each number type has a fixed size and range

Integers come in four sizes, 8, 16, 32 and 64 bits, each signed, int8 to int64, or unsigned, uint8 to uint64. int and uint are 32 or 64 bits wide depending on the platform, and 64 on 64-bit machines. byte is another name for uint8, and rune, which holds one Unicode character, another name for int32. Fractions go in float32 or float64. This program prints the ranges on a 64-bit Mac:

types.go: sizes, ranges and two aliases Go · types.go
// types.go: the sizes and ranges of Go's number types, and two aliases.
package main

import (
	"fmt"
	"math"
	"strconv"
)

func main() {
	fmt.Println("int has", strconv.IntSize, "bits here, up to", math.MaxInt)
	fmt.Println("int8: ", math.MinInt8, "to", math.MaxInt8)
	fmt.Println("uint8:", 0, "to", math.MaxUint8)
	fmt.Println("int32:", math.MinInt32, "to", math.MaxInt32)
	fmt.Println("int64:", math.MinInt64, "to", math.MaxInt64)
	fmt.Println("uint64: 0 to", uint64(math.MaxUint64)) // too big for int, so it is converted

	var b byte = 'A'
	var r rune = '€'
	fmt.Printf("byte is %T, 'A' is %d; rune is %T, '€' is %d\n", b, b, r, r)

	third := 1.0 / 3
	fmt.Println("one third:", float32(third), "as float32,", third, "as float64")
}

Output

int has 64 bits here, up to 9223372036854775807
int8:  -128 to 127
uint8: 0 to 255
int32: -2147483648 to 2147483647
int64: -9223372036854775808 to 9223372036854775807
uint64: 0 to 18446744073709551615
byte is uint8, 'A' is 65; rune is int32, '€' is 8364
one third: 0.33333334 as float32, 0.3333333333333333 as float64

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run types.go

%T names the aliases by their real types, uint8 and int32, and ‘€’ is code point 8364. The last line shows the precision: a float32 prints one third as 0.33333334, a float64 as 0.3333333333333333. Choose a type by what the number holds. Answer the two questions for one number of your own:

Interactive · answer and compare Which number type fits this value? Answer two questions about one number your program stores; the table rules out the types that do not fit and says why.
What does the number hold?
Is it an amount of money?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Six number types against the kinds of value a program stores
Type Counts and positions Same size everywhere Fractions Exact money in cents
int Holds: whole numbers, 64 bits on 64-bit platforms Good what len returns and an index takes Mixed 32 bits on 32-bit platforms, 64 on 64-bit ones Poor whole numbers only: 72 / 5 is 14 Mixed exact, but its size depends on the platform
int64 Holds: whole numbers, 64 bits on every platform Mixed needs int(i) to index a slice Good 64 bits on every platform Poor whole numbers only Good exact whole cents, far beyond any bill
int32, uint16 … Holds: whole numbers of a smaller, fixed width Mixed needs a conversion to index a slice Good matches a field of a file format or protocol Poor whole numbers only Poor int32 cents stop at 21,474,836.47
byte (uint8) Holds: 0 to 255 Poor 255 is its largest value Good 8 bits everywhere Poor whole numbers only Poor holds at most 255 cents
rune (int32) Holds: one Unicode code point Poor meant for characters Good 32 bits everywhere Poor whole numbers only Poor meant for characters, not amounts
float64 Holds: fractions, about 15 significant digits Poor cannot index a slice Good 64 bits everywhere Good keeps fractions, and very large or small values Poor 0.10 has no exact float64 value
How the answers decide
  • “What does the number hold?” A count, a length or a position: rules out byte (uint8), rune (int32) and float64 and adds a caveat to int64 and int32, uint16 …. Counts and positions are what len returns and an index takes, an int; any other integer type needs a conversion at every index.
  • “What does the number hold?” A field of a file format or protocol: rules out float64 and rune (int32) and adds a caveat to int. A field of a format has a width the format fixes, so name that width, such as int32, uint16 or uint8; int changes size by platform.
  • “What does the number hold?” A character of text: rules out int, int64, int32, uint16 … and float64 and adds a caveat to byte (uint8). A character is a rune, such as '€', which is 8364; a byte holds a whole character only in plain ASCII text.
  • “What does the number hold?” A measurement with a fraction: rules out int, int64, int32, uint16 …, byte (uint8) and rune (int32). Only float64 keeps the fraction of a measurement; the integer types drop it.
  • “Is it an amount of money?” Yes: rules out float64, byte (uint8), rune (int32) and int32, uint16 … and adds a caveat to int. Money needs exact whole cents. float64 cannot hold 0.10 exactly, and the small integer types run out of room.

In short: int for counts and positions, a sized type where a file format fixes the width, rune for characters and float64 for measurements. Money goes in an int64 as whole cents, the smallest unit of the currency, because float64 cannot hold 0.10 exactly. A result past a type’s range does not stop the program: it wraps around, so a uint8 at 255 plus 1 is 0. At run time nothing warns when that happens, so choose a type wide enough for the largest value the program will ever hold.

Checkpoint

Check: Number types, sizes and ranges

  1. Question 1 of 2 How many bits does an int have on a 64-bit platform?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 64

    int and uint are 32 or 64 bits depending on the platform, and 64 on 64-bit machines. When the width must be the same everywhere, name it: int64.

  2. Question 2 of 2 A file format stores the length of each record in 2 bytes, as an unsigned number. Which Go type matches it?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: uint16

    Where a file format or protocol fixes a width, the sized type says so in the code: int8 to int64, uint8 to uint64.

Go converts only where you write a conversion

A conversion: An expression such as int64(seats) that makes a value of the named type from another value. Go converts between types only where the code writes a conversion; untyped constants are the one exception. is the name of a type used like a function: int64(seats) makes an int64 from an int. Go never adds one for you, so even int and int64 cannot meet in one expression:

mismatch.go: an int plus an int64 Go · mismatch.go
// mismatch.go: an int and an int64 in one expression.
package main

import "fmt"

func main() {
	var seats int = 72
	var berths int64 = 8
	fmt.Println(seats + berths)
}

Output (exit status 1)

Printed as an error (standard error)

# command-line-arguments
./mismatch.go:9:14: invalid operation: seats + berths (mismatched types int and int64)

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run mismatch.go

The fix is a conversion on one side. This program converts between number types and between numbers and text:

conversions.go: every conversion written out Go · conversions.go
// conversions.go: Go converts between types only where you write it.
package main

import (
	"fmt"
	"strconv"
)

func main() {
	var seats int = 72
	var berths int64 = 8
	total := int64(seats) + berths // int and int64 do not mix without a conversion
	fmt.Println("total:", total)

	perCoach := float64(seats) / 5 // 72 / 5 with integers would be 14
	fmt.Println("per coach:", perCoach, "as int:", int(perCoach))
	debt := -2.9
	fmt.Println("int(-2.9):", int(debt)) // the fraction is dropped, toward zero

	code := 65
	fmt.Println(string(rune(code)), strconv.Itoa(code)) // the character 65, and 65 as text
	n, err := strconv.Atoi("72")
	fmt.Println(n+1, err)
	_, err = strconv.Atoi("seventy")
	fmt.Println(err)
}

Output

total: 80
per coach: 14.4 as int: 14
int(-2.9): -2
A 65
73 <nil>
strconv.Atoi: parsing "seventy": invalid syntax

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run conversions.go

A float converts to an integer by dropping its fraction, toward zero: int(14.4) is 14 and int(-2.9) is -2. An untyped constant: A constant with no type yet, such as 5, 2.5 or "hi". It takes the type its use needs, as long as its value fits that type, and has a default type, such as int or float64, where nothing else gives it one. More in “Constants, untyped values and iota” such as 5 has no type of its own, so it takes the type of the other operand without a conversion. Step through that division:

Interactive · stage by stage How Go gives float64(seats) / 5 its type Step through the division from conversions.go, then the same division without the conversion.
How Go gives float64(seats) / 5 its type, step 6 of 6. Showing seats, float64(seats), the constant 5, 5 becomes a float64, 72 / 5 = 14.4 (seats / 5 = 14, an int). In focus: no-convert, 72 / 5 = 14.4.seats / 5: int, 14seatsan int variable, 72float64(seats)a new float64 value, 72the constant 5untyped: no type yet5 becomes a float64it takes the other side's type72 / 5 = 14.4seats / 5 = 14, an int

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. An int. seats is an int holding 72. An int never meets a float64 in one expression without a conversion, not even in a division.
  2. The conversion. float64(seats) is a conversion. It makes a new float64 value, 72, and leaves seats itself an int.
  3. An untyped constant. 5 is a constant with no type yet. When the other operand of an operator has a type, Go converts an untyped constant to it on its own.
  4. Both sides match. So 5 becomes the float64 value 5, and both sides of the division have the same type, which every arithmetic operator needs.
  5. A float64 result. Dividing two float64 values gives 14.4. int(perCoach) then converts back to int by dropping the fraction, which gives 14.
  6. Without the conversion. seats / 5 divides two ints, because 5 takes seats' type, int. Integer division drops the remainder, so the result is 14 and the .4 is gone before any conversion could keep it.

Between numbers and text, use the package strconv: strconv.Itoa(65) gives “65”, and strconv.Atoi reads text back, with an error for text that is not a whole number. string(65) gives “A”, the character with code 65, which is almost never what was meant. go vet reports it:

stringint.go: string(seat) Go · stringint.go
// stringint.go: string(n) compiles, but it does not give the digits.
package main

import "fmt"

func main() {
	seat := 65
	fmt.Println("seat " + string(seat))
}
string(seat) runs, and go vet explains it Python · vet_session.py
from session import run

# string(n) compiles and runs, and go vet explains what it really does.
run(
    """
go run stringint.go
go vet stringint.go
""",
    expect_failure=["go vet stringint.go"],
)

Output

$ go run stringint.go
seat A
$ go vet stringint.go
stringint.go:8:24: conversion from int to string yields a string of one rune, not a string of digits
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 vet_session.py

Checkpoint

Check: Explicit conversions and strconv

  1. Question 1 of 2 This does not compile. Which change makes it compile and keep the fraction?

    Read the code, then choose one answer.

    var count int = 3
    var weight float64 = 2.5
    total := count * weight
    Show the answer: Question 1 of 2

    Answer: total := float64(count) * weight

    An arithmetic operator needs operands of the same type, so one side gets a conversion. Convert the one that should take on the other's type: here the int, so that the fraction survives.

  2. Question 2 of 2 n := 72. What do string(rune(n)) and strconv.Itoa(n) give?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: "H" and "72"

    Use strconv for numbers as text, Itoa and FormatInt one way and Atoi and ParseInt the other. string(rune(n)) is for when you really mean a character.

A string holds bytes, and a bool holds only true or false

A Go string is a sequence of bytes that never changes once it exists. A string literal holds its text as UTF-8: The encoding of Go source code and string literals: each Unicode character takes one to four bytes, so 'A' takes one byte and '₹' three. len of a string counts these bytes., where ‘€’ takes three bytes, and len counts bytes:

strings_bools.go: bytes, joins and bools Go · strings_bools.go
// strings_bools.go: a string is a sequence of bytes; a bool is true or false.
package main

import (
	"fmt"
	"strconv"
)

func main() {
	price := "€1999"
	fmt.Println(len(price), "bytes") // € takes 3 bytes in UTF-8
	fmt.Println(price[0], price[3], string(price[3]))
	fmt.Println(price + " with tax") // + makes a new string

	paid := len(price) > 0 // a comparison gives a bool
	fmt.Println(paid, !paid, paid && false)
	ok, err := strconv.ParseBool("yes")
	fmt.Println(ok, err)
}

Output

7 bytes
226 49 1
€1999 with tax
true false false
false strconv.ParseBool: parsing "yes": invalid syntax

Recorded with Go 1.27.1 on macOS 26 arm64. To run it yourself: go run strings_bools.go

“€1999” has length 7, not 5. Indexing gives bytes: price[0] is 226, the first byte of ‘€’, and price[3] is 49, the digit 1. + builds a new string, and price[0] = 'R' does not compile, because a string’s bytes cannot be assigned.

A bool is true or false and nothing else. Comparisons produce one, and !, && and || combine them. No number stands in for a bool, so if count {} with an int does not compile. strconv.ParseBool reads “true”, “false”, 1, 0 and a few short forms, and in the run it refused “yes”.

Checkpoint

Check: Strings as bytes, and bools

  1. Question 1 of 2 What is len("€500")?

    Type a number.

    A hint

    Count the bytes of each character in UTF-8, as "€1999" did.

    Show the answer: Question 1 of 2

    Answer: 6 bytes

    len counts bytes. '€' takes three bytes in UTF-8 and each digit one, so the length is 3 + 3 = 6.

  2. Question 2 of 2 found := 1. Which of these conditions compiles?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: if found == 1

    No number stands in for a bool in Go. Write the comparison you mean, such as found != 0 or found == 1.

Overflow, division and remainder, reproduced Pro: opens with a Pro, Premium or Ultimate pass

Integer arithmetic in Go never stops a program because a result is too big, and it drops the fraction of every quotient toward zero. Here both rules run on real numbers, with the two ways a division by zero is caught.

In this part:

  • What wraps at run time and what the compiler refuses
  • Division drops the fraction toward zero
  • A division by zero, caught at compile time or at run time
  • Catching an overflow before it happens

1 diagram · 6 runnable examples (Go) · about 6 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Money without float drift: cents, rounding and a fair split Pro: opens with a Pro, Premium or Ultimate pass

Floating-point numbers are the wrong home for money, and their errors are small enough to pass tests that use round numbers. This part measures the drift, keeps amounts in whole cents, writes the rounding down, and splits a bill so that the shares add up to the total.

In this part:

  • Why 0.1 and 0.2 do not add up to 0.3, measured
  • Amounts as whole cents, with the rounding written down
  • Splitting 1,000.00 among three without losing a cent

1 diagram · 3 runnable examples (Go) · about 6 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Practise

This self-check covers number types, conversions, strings and bools. The session starts where you have been least sure, and a wrong choice tells you what it misses:

Practice that adapts to you

Practise this lesson

9 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 9 byte is another name for which type?

    Choose one answer.

    Show the answer: Question 1 of 9

    Answer: uint8

    byte and rune are the only aliases among the number types: byte for uint8 and rune for int32.

  2. Question 2 of 9 var r rune = 'A'. What does fmt.Println(r) print?

    Choose one answer.

    Show the answer: Question 2 of 9

    Answer: 65

    A rune holds a Unicode code point as a number: 'A' is 65 and '€' is 8364, as types.go printed.

  3. Question 3 of 9 A function returns the position of a value in a slice, or -1 when it is not there. Which type should it return?

    Choose one answer.

    Show the answer: Question 3 of 9

    Answer: int

    Choose the type the rest of the language uses for the same idea. For counts and positions that is int.

  4. Question 4 of 9 What does int(f) give when f := 3.99?

    Choose one answer.

    Show the answer: Question 4 of 9

    Answer: 3

    int(f) truncates toward zero: 3.99 gives 3 and -2.9 gives -2, as conversions.go printed.

  5. Question 5 of 9 What does this print?

    Read the code, then choose one answer.

    n, err := strconv.Atoi("12a")
    fmt.Println(n, err)
    Show the answer: Question 5 of 9

    Answer: 0 strconv.Atoi: parsing "12a": invalid syntax

    strconv's parse functions return a value and an error. On a syntax error the value is 0, so always check err before using it.

  6. Question 6 of 9 Does this compile, and what does it print?

    Read the code, then choose one answer.

    var ratio float64 = 0.5
    fmt.Println(ratio * 3)
    Show the answer: Question 6 of 9

    Answer: It compiles and prints 1.5, because the constant 3 takes ratio's type

    Typed values never convert on their own, but untyped constants do, as long as the value fits the type they take.

  7. Question 7 of 9 price := "€1999", then price[0] = 'R'. What happens?

    Choose one answer.

    Show the answer: Question 7 of 9

    Answer: It does not compile: a string's bytes cannot be assigned

    Once a string exists, its bytes never change. Build a new string with +, strings.Builder or a conversion from a []byte.

  8. Question 8 of 9 What does this print?

    Read the code, then choose one answer.

    s := "go€"
    fmt.Println(len(s), s[1])
    Show the answer: Question 8 of 9

    Answer: 5 111

    A string is a sequence of bytes: len counts them and an index reads one. Characters come from range loops and []rune conversions, which the strings lessons cover.

  9. Question 9 of 9 What does strconv.ParseBool("T") return?

    Choose one answer.

    Show the answer: Question 9 of 9

    Answer: true and a nil error

    A bool comes from text only through ParseBool, from a comparison, or from true and false themselves.

Interview questions

Warm-up (fresher): Is int the same type as int64 on a 64-bit machine?

No. They have the same size there, but they are different types, so an expression that mixes them does not compile until one side is converted. The size of int belongs to the platform, 32 or 64 bits, while int64 is 64 bits everywhere, so use int64 when the width matters.

Three longer questions of the module bank build on this lesson:

  1. Fresher to mid

    A daily report converts each order's float64 total to cents and adds them up. After 40,000 orders it is about 2,300 cents below the bank's statement, though every order prints correctly. Why does that happen, and how would you fix the code and the stored data?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A metric counts the bytes uploaded in an int32 field. After one large upload the dashboard shows a negative number. Explain what happened, how code could have caught it before it happened, and which type you would use instead.

    Model answer, Pro. First step and follow-ups

  3. Fresher to mid

    A colleague builds cache keys with key := "order:" + string(order.ID). For the IDs 65 and 9731 the keys come out as "order:A" and "order:☃". What went wrong, how does Go's tooling catch it, and how do you convert numbers to text and back safely?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Every number type has a fixed size: int is 64 bits on 64-bit platforms, byte is uint8 and rune is int32.
  • Go converts between types only where you write a conversion, and a float converts to an integer by dropping the fraction toward zero.
  • strconv converts between numbers and text; string(n) gives a character, which go vet reports.
  • A string is a sequence of bytes that cannot change, len counts bytes, and a bool is only true or false.

Terms in this lesson

conversion
An expression such as int64(seats) that makes a value of the named type from another value. Go converts between types only where the code writes a conversion; untyped constants are the one exception.
UTF-8
The encoding of Go source code and string literals: each Unicode character takes one to four bytes, so 'A' takes one byte and '₹' three. len of a string counts these bytes.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.