left-icon

Go Succinctly®
by Mark Lewin

Previous
Chapter

of
A
A
A

CHAPTER 5

Basic Data Types

Basic Data Types


Basic data types in Go consist of integers, floating-point numbers, strings, and Booleans. These are the Go “primitives” from which the more complex types are built.

Numeric data types

Integers

Integers are simply numbers without a decimal part. In simple terms, they are “whole numbers.” So 5, 34, and 7,424 are integers. 3.14, 22.7, and 0.01098 are not.

Although we like to think of numbers in terms of a 10-based numbering system, computers store them in binary form. The size of the number a computer can store depends on the amount of memory space allocated to the task. For example, a 4-bit integer can store 0000 (zero), 0001 (one), 0011 (three), and so on up to 1111 (15). So a 4-bit integer can represent the numbers zero to 15.

Go’s integer data types range in storage capacity from 8 bits to 64 bits. If you need that level of control over memory allocation, you can choose from uint8, uint16, uint32, uint64, and from int8, int16, int32, and int64.There are also variations called uints, which store only unsigned integers: bytes (equivalent to uint8) and runes (equivalent to uint32). However, gone are the days where memory is limited for many applications, and for most use cases the simple int data type will be more than adequate. It corresponds to either int32 or int64 and can store numbers from -2147483648 to 2147483647 and from -9223372036854775808 to 9223372036854775807, respectively.

If you need to work with larger integers than that, consider using the uint data type, which is either uint32 or uint64 and can store 0 to 4294967295 or 0 to 18446744073709551615, respectively.

Floating-point numbers

Floating-point numbers, or “real numbers,” contain a decimal part. The important thing to realize is that they are often inexact and their accuracy depends on the number of decimal places the computer can store. As with integers, there are several different data types you can choose from, all offering different levels of precision, although the storage mechanism is not the same as for integer values. For the vast majority of cases, stick with float32 and float64 and consult the documentation if you have special requirements.

Working with numeric data

To assign an integer value to a variable, simply specify the number. To force a variable to store a number as a floating-point value, ensure that you specify the decimal component, even if it is zero.

Code Listing 8

package main

import (

     "fmt"

)

func main() {

     int1 := 2

     int2 := 3

     

     fp1 := 22.0

     fp2 := 7.0

     

     fmt.Printf("%d + %d = %d\n", int1, int2, int1 + int2)

     fmt.Printf("%f / %f = %f\n", fp1, fp2, fp1 / fp2)    

}

2 + 3 = 5

22.000000 / 7.000000 = 3.142857

Note that even though we are sure that the values of fp1 and fp2 are exact, the result of fp1/fp2 is inexact, and the accuracy depends on the data type being used to hold it. Because we have allowed Go to infer the type for us, what actual type is Go using?

We can discover this by using Go’s reflect library, which allows Go programs to interrogate themselves for information.

Code Listing 9

package main

import (

  "fmt"

  "reflect"

)

func main() {    

     fp1 := 22.0

     fp2 := 7.0

     

     result := fp1/fp2

     fmt.Printf("%f / %f = %f\n", fp1, fp2, result)

           

  fmt.Printf("fp1 is type: %s\n", reflect.TypeOf(fp1))

  fmt.Printf("fp2 is type: %s\n", reflect.TypeOf(fp2))

  fmt.Printf("result is type: %s\n", reflect.TypeOf(result))

}

22.000000 / 7.000000 = 3.142857

fp1 is type: float64

fp2 is type: float64

result is type: float64

If you want to specify the type of your float explicitly (such as float32), you could use one of the following constructs:

var fp1 float32;

fp1 = 3.14

or

fp1 := float32(3.14)

If you want to cast from one type to another, use the second form shown previously:

i := 373

f := float64(i)

u := uint(f)

If you declare a numeric value but don’t give it a value, it is automatically assigned the value of zero.

Booleans

A Boolean is a special type of integer that has only two values, usually denoted by true and false. Boolean values are used for logical operations.

When you define a Boolean variable without assigning a value to it, it is given the default value of false.

As well as checking the value held by a Boolean variable, you can also use Boolean values with the three logical operators && (and), || (or), and ! (not). The following example shows how these work:

var trueValue bool

trueValue = true                                              

falseValue := false

fmt.Println(trueValue && trueValue)    // true

fmt.Println(trueValue && falseValue)   // false

fmt.Println(trueValue || trueValue)    // true

fmt.Println(trueValue || falseValue)   // true

fmt.Println(!trueValue)               // false

Strings

Strings are absolutely fundamental to computer programs in all languages, and Go provides a lot of support for creating and manipulating strings.

You can define a string in Go by surrounding it with double quotes, as we’ve seen many times already, or by backquotes (`). The difference is that if you use double quotes, you cannot include newlines. However, double-quoted strings do allow you to insert special “escape characters,” such as \n for a carriage return and \t for a tab. Anything inside backquotes is used completely literally. For example:

str1 := "There is a tab between this\tand this"

str2 := `There is a tab between this\tand this`

fmt.Println(str1)

fmt.Println(str2)

This produces the following:

There is a tab between this  and this

There is a tab between this\tand this

If you declare a string variable and don’t assign a value, Go gives it a default value of an empty string (“”).

Common string operations

Concatenation

You can join two or more strings together to create a new, longer string by using the concatenation operator +. Note that, as with most languages, Go strings are immutable. The sequence of bytes in a string never changes, but you can always assign a new value to a string variable.

str1 := "This is a string "

str2 := " which is now much longer"

fmt.Println(str1 + str2)

This produces:

This is a string which is now much longer

The backquotes approach is very useful when you want to include double quotes within the string:

str1 := `I can include "double quotes" in this string without any issues`

str2 := "The use of "double quotes" within this string will cause a compiler error"

Length

You can get the length of a string by using the len() function.

str := "This is a string"

fmt.Println(len(str)) // Displays 17

Substrings

You can return a character or characters from specific positions in the string by including square brackets, which contain a starting position and ending position separated by a colon. The first character in a string is at position zero, so the total number of positions equals (len(str)-1). If you want the starting position to be either the at beginning or at the end of the string, just omit the position number.

str := "The elephants of spring are tickling my frying spoon"

fmt.Println(str[0:4])   // "The "

fmt.Println(str[17:23]) // "spring"

fmt.Println(str[:13])   // "The elephants"

fmt.Println(str[31:])   // "frying spoon"

Comparing strings

You can compare strings with the usual comparison operators: == (for equality), < (less than), > (greater than), and so on. The comparison is byte by byte, and the result depends on the natural lexicographic ordering (namely, how the strings might appear in a dictionary). For this example, we can use Go’s if/else construct, which is very similar to how you might use if/else in another language, but note that in Go, you don’t need parentheses around the conditions.

str1 := "abc"

str2 := "abd"

if str1 > str2 {

     fmt.Println("abc is greater than abd")

} else {

     fmt.Println("abd is greater than abc")

}

This produces:

abd is greater than abc

We’ll look more at the if/else statement and the other Go control structures in the next chapter.

Converting between numbers and strings

Because Go is a statically typed language, you cannot use strings where you would expect a number, and vice versa.

For example:

int1 := 48

str1 := "My number is "

str1 = str1 + int1

// "invalid operation: str1 + int1 (mismatched types string and int)"

str2 := "4"

result := 48 / str2

fmt.Println(result)    

// "cannot convert 48 to type string"

// "invalid operation: 48 / str2 (mismatched types int and string)"

The solution is to use the functions in the strconv package, which will provide a number of different ways for converting between strings and other data types. The most common functions are:

  • strconv.Atoi() : Converts a string to an integer
  • strconv.Itoa() : Converts an integer to a string

The itoA() function always works, so there is no facility for returning an error. But the Atoi() function returns two values: the converted value, and an object containing information about any errors resulting from the conversion. So we need to assign two variables to receive those returned values:

i,err := strconv.Atoi("32")

If we’re not interested in whatever information err holds (that is, if we’re confident that the conversion is straightforward and not going to cause an error condition), then by defining it we are duty-bound by Go to use it somewhere in our program. If we don’t, we’ll get a compiler error:

err declared and not used

The solution is to use another Go idiom: the empty variable (_). This will provide the “placeholder” for the returned value, but will allow us to ignore it:

i, _ := strconv.Atoi("32")

Tip: Use the empty variable (_) anywhere Go requires you to declare a variable that you don't intend to use anywhere else in your program. Otherwise, you will get a compilation error (Go likes to keep a tidy house and hates anything that is declared and never used).

The result of fixing these data-type issues can be seen in Code Listing 10:

Code Listing 10

package main

import (

     "fmt"

     "strconv"

)

func main() {   

  int1 := 48

  int1_as_string := strconv.Itoa(int1)

  str1 := "My number is "

  str1 = str1 + int1_as_string

  fmt.Println(str1)

     str2 := "4"

  str2_as_integer, _ := strconv.Atoi(str2)

  result := 48 / str2_as_integer

  fmt.Printf("%s / %s is %d\n", int1_as_string, str2, result)    

}

My number is 48

48 / 4 is 12

There are many other functions for converting strings to and from other data types within the strconv package:

  • ParseBool(), ParseFloat(), ParseInt(), and ParseUint() convert strings to values.
  • FormatBool(), FormatFloat(), FormatInt(), and FormatUnit() convert values to strings.

Consult the strconv package documentation for a full list.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.