10 minutes read

In this topic, you will extend your knowledge about variable types, learn how to convert one type to another, and get acquainted with variable overflow.

Conversion of numbers

Golang is a strongly-typed programming language, and information about operations with variables gives you more understanding of how Go works. Let's look at a code example.

At the beginning of the piece of code below, we create a variable with the int64 type, because it is the largest variable available. Next, we create an int8 variable. Converting integer types is easy: just take a variable or a value, add brackets around it, and you will get a value of the new type:

package main

import "fmt"

func main() {
    var longInt int64 = 4295033104
    var smallInt int8 = 42

    from64To32 := int32(longInt) // convert int64 to int32
    from8To32 := int32(smallInt) // convert int8 to int32

    fmt.Println(longInt)
    fmt.Println(smallInt)

    fmt.Println(from64To32)
    fmt.Println(from8To32)
}

// Output:
// 4295033104
// 42
// 65808
// 42

The same principle also applies to all other int and uint types. Just remember that if you convert a bigger value to a smaller one or convert signed and unsigned values, the result will be the smallest possible value between the original value and the maximum capacity of the new type.

Type conversion between float and integer numbers works the same way between integers. Some examples are below:

package main

import (
	"fmt"
	"math"
)

func main() {
	var floatVar float32 = 12.5
	var longInt int64 = 42
	var borderInt uint64 = uint64(math.Pow(2, 64))

	floatToInt := int8(floatVar)
	intToFloat := float32(longInt)
	borderToFloat := float32(borderInt)

	fmt.Println(floatToInt)
	fmt.Println(intToFloat)
	fmt.Println(borderToFloat)
}

// Output:
// 12
// 42
// 9.223372e+18

As a result of the third conversion, we get a value beyond the type range (for 32-bit float type). Despite that, the conversion occurs without errors; the number just gets an exponent view.

Trying to convert float types to integers returns a number without the fractional part. If you try to convert an integer back to a float number, the value of the number will not change. Thus, you should make sure to use the right variable type; otherwise, you will get an incorrect answer.

Overflow

What happens if a mathematical expression returns a value that goes beyond the variable range? Let's see: we will take two int8 variables, set their values close to the type range boundary, and try to add them.

package main

import "fmt"

func main() {
    var rightBorder1 int8 = 127
    var rightBorder2 int8 = 127

    overflowVar := rightBorder1 + rightBorder2

    fmt.Println(overflowVar)
}

// Output:
// -2

The return value is rather unexpected… Why don't we get 254? Let's look into it. The expression contains two strongly-typed variables of the int8 type, and the third variable overflowVar has the same int8 type. The maximum value for int8 is 127, so 254 just can't be there. It is clear but doesn't explain the appearance of -2 as the return value.

What has happened here is called overflow. It occurs when you try to set a value that goes beyond the supported range. You can't have an unsupported value assigned to a variable, but you can get this value via arithmetic expressions. Have a look at the example below:

package main

import "fmt"

func main() {
    // var unsupInt8 int8 = 128
    // error: constant 128 overflows int8
    // var unsupUint8 uint8 = 256
    // error: constant 256 overflows uint8

    var leftInt8 int8 = -128
    var rightUint8 uint8 = 255

    fmt.Printf("origin: %d | sub 1: %d\n", leftInt8, leftInt8 - 1)
    fmt.Printf("origin: %d | add 1: %d\n", rightUint8, rightUint8 + 1)
}

// Output:
// origin: -128 | sub 1: 127
// origin: 255 | add 1: 0

You can see that when a variable has an overflow on one boundary, it goes to the opposite boundary.

Boolean conversion

Every programming language has a mechanism that compares types and allows performing conversion operations. Golang is no exception. However, a boolean type is unique — it can't be compared to other types, and the code below will return an error:

a := bool(0)     // error!
b := bool("yes") // error!
c := bool(123)   // error!

You can use comparison operations to convert numbers or strings to the boolean type. They will return a boolean value. All you need to do is compare a number with zero or an empty string:

package main

import "fmt"

func main() {
    var numberVar int8 = 12
    var stringVar string = ""

    var numFlag bool
    var strFlag bool

    // number to bool
    numFlag = numberVar != 0

    // string to bool
    strFlag = stringVar != ""

    fmt.Println(numFlag)
    fmt.Println(strFlag)
}

// Output:
// true
// false

Bytes and runes

Bytes and runes are aliases for integer number types and function like integers. All conversion and math operations supported for integers and floats also work for bytes and runes. Moreover, bytes and runes can be compared to strings under certain conditions. Some rules about the conversion of numbers to strings are the following:

  • the number should have an integer type;

  • all symbols have a numeric code, but not all codes have a symbol;

  • numeric code is mapped to a character encoding.

Now, let's try to convert some numbers to strings:

package main

import "fmt"

func main() {
	var intNumber int8 = 1
	var byteNumber byte = 42
	var runeNumber rune = 43

	fromInt := string(intNumber)
	fromByte := string(byteNumber)
	fromRune := string(runeNumber)
	fromConst := string(44)

	fmt.Println(fromInt)
	fmt.Println(fromByte)
	fmt.Println(fromRune)
	fmt.Println(fromConst)
}

// Output:
//
// *
// +
// ,

We expect the output with four symbols, but there are only three of them. The first line of our output is empty, which means that the current character encoding table doesn't have a symbol with the code “1” or that it's a control character. The output may suggest which character encoding table is used in the system. For example, the char “percent” has the code 37. Using the Charset site, you can find out that the encoding for these symbols is “UTF-8”.

Strings

In the previous section, we've seen how to convert other types to strings. Now, let's consider the reverse process:

  • we can convert a string to a slice;

  • the slice must have the rune or byte type.

You can see an example of such operation below:

package main

import "fmt"

func main() {
	// var singleChar string = "+"
	// a := byte(singleChar) // conversion error
	// b := int(singleChar)  // conversion error

	var helloString string = "Hello!"

	latToBytes := []byte(helloString)
	latToRunes := []rune(helloString)

	fmt.Println(latToBytes)
	fmt.Println(latToRunes)
}

// Output:
// [72 101 108 108 111 33]
// [72 101 108 108 111 33]

As you can see, it's easy to use! Just add square brackets before the type name to represent numbers in a slice.

Conclusion

In this topic, we've covered the theory of type conversion. In particular, you should remember the following points:

  • conversion is based on the types we compare (numbers, boolean values, strings, slices);

  • conversion and math operations can be the cause of overflow;

  • boolean conversion passes using comparison operations;

  • any integer number can be converted to a string;

  • strings can be converted to slices of the byte or rune type.

32 learners liked this piece of theory. 3 didn't like it. What about you?
Report a typo