Type Conversion
Go never converts between types behind your back. Adding an int to a float64, or an int32 to an int64, is a compile error until you convert one of them explicitly. This lesson shows the conversion syntax, what conversions do to values, and how numbers and strings are converted.
No automatic conversions
package main import "fmt" func main() { count := 3 price := 2.5 var big int64 = 10 fmt.Println(count*price, count+big) }
./main.go:9:14: invalid operation: count * price (mismatched types int and float64) ./main.go:9:27: invalid operation: count + big (mismatched types int and int64)
This feels strict at first, but it removes a whole category of bugs where precision is lost or values overflow without anyone noticing.
Converting with T(value)
To convert, write the target type like a function call:
package main import "fmt" func main() { count := 3 price := 2.5 var big int64 = 10 fmt.Println(float64(count) * price) fmt.Println(int64(count) + big) total, n := 17, 5 fmt.Println(total/n, float64(total)/float64(n)) }
7.5 13 3 3.4
Converting total and n to float64 before dividing is the standard way to get a fractional average from whole numbers.
What conversions do to numbers
package main import "fmt" func main() { price := 9.99 fmt.Println(int(price), int(-price)) // drops the fraction (toward zero) big := 300 fmt.Println(uint8(big)) // keeps the low 8 bits: 300 - 256 neg := -1 fmt.Println(uint32(neg)) // same bits, read as unsigned f := 16777217.0 fmt.Println(float32(f)) // float32 can't hold every integer this large }
9 -9 44 4294967295 1.6777216e+07
Converting a float to an integer truncates; it doesn't round. (Converting the constant 9.99 directly, as in int(9.99), is a compile error instead — the compiler refuses to throw away the fraction of a constant.) Use int(math.Round(x)) if you want rounding. Converting to a smaller integer type keeps only the bits that fit, so check the range first if the value could be too large.
Untyped constants
A literal like 2 or 0.5 has no fixed type until it's used, so it fits wherever it makes sense without a conversion:
package main import ( "fmt" "time" ) func main() { price := 2.5 fmt.Println(price * 2) // 2 becomes a float64 here var small int8 = 100 fmt.Println(small + 20) // 20 becomes an int8 fmt.Println(3 * time.Second) // 3 becomes a time.Duration }
5 120 3s
Lesson 10 explains untyped constants in more detail.
Numbers and strings
To turn a number into its decimal text, use the strconv package or fmt.Sprint — not string(n). Converting an integer with string() treats it as a Unicode code point, which is almost never what you want, so go vet reports it:
package main import "fmt" func main() { n := 65 fmt.Println(string(n)) }
main.go:7:14: conversion from int to string yields a string of one rune, not a string of digits
package main import ( "fmt" "strconv" ) func main() { n := 65 fmt.Println(string(rune(n))) // if you really want the character: say so fmt.Println(strconv.Itoa(n) + " items") fmt.Println(fmt.Sprint(n, " items")) qty, err := strconv.Atoi("12") fmt.Println(qty*2, err) price, err := strconv.ParseFloat("19.95", 64) fmt.Println(price, err) _, err = strconv.Atoi("twelve") fmt.Println(err) }
A 65 items 65 items 24 <nil> 19.95 <nil> strconv.Atoi: parsing "twelve": invalid syntax
Parsing can fail, so the parsing functions return a value and an error. Always check the error (lesson 44); <nil> means no error. Lesson 21 covers strconv fully.
Strings, bytes and runes
A string can be converted to a slice of bytes or a slice of runes (Unicode code points) and back. The conversions copy the data:
package main import "fmt" func main() { s := "héllo" b := []byte(s) r := []rune(s) fmt.Println(len(b), b) fmt.Println(len(r), r) r[1] = 'e' fmt.Println(string(r), s) }
6 [104 195 169 108 108 111] 5 [104 233 108 108 111] hello héllo
Conversions between named types
A type you define with type (lesson 36) is a distinct type, even when it has the same underlying type as another. Values move between them only by conversion:
package main import "fmt" type Celsius float64 type Fahrenheit float64 func toF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) } func main() { temp := Celsius(21.5) fmt.Println(toF(temp)) fmt.Println(float64(temp) + 1.5) }
70.7 23
Distinct types like these let the compiler stop you from mixing up Celsius and Fahrenheit, metres and feet, or user IDs and order IDs.
Try it yourself
Calculate the average of three test scores, rounded to one decimal place.
85.33333333333333 85.3
iota.