7. Type conversions

📖 Reading · 8 min
💡 Every code box below is live — edit it and hit Run.

Go will not mix types behind your back. Add an int to a float64 and it won't quietly convert one for you — it's a compile error. That feels strict at first, but it means the surprising bugs of implicit conversion simply can't happen. When you want a conversion, you ask for it explicitly.

No implicit mixing

Run this and read the error, then we'll fix it:

package main

import "fmt"

func main() {
    count := 3          // int
    price := 4.5        // float64
    total := count * price // error: mismatched types
    fmt.Println(total)
}

Go stops you because count is an int and price is a float64, and it won't guess which one you meant to change.

Conversion syntax: T(value)

To convert, wrap the value in the target type like a function call: float64(count), int(price), string(...). Here's the fix:

package main

import "fmt"

func main() {
    count := 3
    price := 4.5
    total := float64(count) * price // now both are float64
    fmt.Printf("%.2f\n", total)
}

Converting truncates, it doesn't round

Turning a float64 into an int throws away the fractional part — it truncates toward zero, it does not round:

package main

import "fmt"

func main() {
    a := 3.9
    b := -3.9
    fmt.Println(int(a)) // 3, not 4
    fmt.Println(int(b)) // -3
}

Note we convert variables here. Converting a fractional constant directly — int(3.9) — is actually a compile error in Go (constant 3.9 truncated to integer): the compiler won't silently drop the .9 from a literal. Truncation only happens when you convert a value that's already a float at runtime.

If you want rounding, that's a deliberate step (add 0.5 before converting, or use math.Round) — the conversion alone never rounds for you.

Integer division is its own trap

This isn't a conversion, but it bites people constantly. Divide two integers and you get an integer result — the remainder is discarded — before any float ever enters the picture:

package main

import "fmt"

func main() {
    fmt.Println(7 / 2)               // 3  (integer division)
    fmt.Println(float64(7) / 2)       // 3.5
    fmt.Println(float64(7 / 2))       // 3  — too late! divided as ints first
}

The order matters: convert before dividing, not after. float64(7 / 2) does the integer division first, then converts the 3.

Strings are not numbers

A very common beginner mistake: converting an int to a string with string(65) does not give you "65". It interprets the number as a Unicode code point — 65 is the letter A:

package main

import "fmt"

func main() {
    fmt.Println(string(rune(65))) // "A", not "65"
}

To turn a number into its text form, you use the strconv package (or fmt.Sprintf), which we'll see properly in the standard-library module:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    n := 65
    text := strconv.Itoa(n) // "Itoa" = integer to ASCII
    fmt.Println(text + text) // "6565" — string concatenation

    viaFmt := fmt.Sprintf("%d", n)
    fmt.Println(viaFmt)
}

Your turn

You have total := 7 and people := 2 (both int). Compute the share each person gets as a float64 and print it to 2 decimals — exactly:

Each person pays 3.50

Watch the integer-division trap: convert before you divide.

package main

import "fmt"

func main() {
    total := 7
    people := 2
    // compute the per-person share as a float64 and print it
}
package main

import "fmt"

func main() {
    total := 7
    people := 2
    share := float64(total) / float64(people)
    fmt.Printf("Each person pays %.2f\n", share)
}

That closes out types. Next module: making decisions and repeating work — Go's control flow.