02 Data Types What Are the Essential Data Types You Must Know

02 Data Types - What are the Essential Data Types You Must Know #

The exercise in the previous lesson was to print your own name. This task is relatively simple, involving text replacement. You just need to modify the “Hello World” in my example to your own name. For example, using my name as an example, replace it with “飞雪无情”.

After studying the previous lesson, you should have a basic understanding of the program structure of the Go language and be ready with the corresponding development environment. However, a complete project requires more complex logic, not just a simple “Hello World”. This logic is composed of variables, constants, types, function methods, interfaces, and structures. In this lesson, I will introduce them to you and make your Go language programs more lively.

Variable Declaration #

Variables represent mutable data types, which means they can be modified once or multiple times during program execution.

In Go language, you can use the var declaration statement to define a variable. When defining a variable, you need to specify its type, give it a name, and set its initial value. Therefore, the format to declare a variable with var is as follows:

var variableName type = expression

Now I will show you an example to demonstrate how to define a variable and set its initial value:

ch02/main.go

package main

import "fmt"

func main() {
    var i int = 10
    fmt.Println(i)
}

In the above example, var i int = 10 defines a variable named i with the type int (integer) and sets its initial value as 10.

To run the program, I added a line fmt.Println(i). You have seen it in the previous lesson, and it is used to print the value of variable i.

Doing so has several reasons: first, in Go language, the variables we define must be used, otherwise the program will fail to compile. This is a good feature of Go language that prevents defining unused variables and wasting memory. Second, when running the program, you can check the result of variable i.

To run the program, enter the command go run ch02/main.go and press enter, you will see the following result:

$ go run ch02/main.go
10

The result is 10, which is the same as the initial value of the variable.

Since Go language has type inference feature, you don’t have to explicitly specify the type of the variable. Instead, you can let Go language infer it by itself. For example, the variable i can also be declared as follows:

var i = 10

In this case, the type of variable i is automatically inferred as int.

You can also declare multiple variables at once by putting the variables you want to declare in a pair of parentheses, as shown in the code below:

var (
    j int = 0
    k int = 1
)

Similarly, due to type inference, the above multiple variable declarations can also be written as:

var (
    j = 0
    k = 1
)

This is even more concise.

In fact, not only int type, but also the basic types I will introduce later, such as float64, bool, string, etc., can be automatically inferred, which means the type definition can be omitted.

Project Directory Structure for Demonstration #

In order to help you better understand the examples I demonstrate, I will provide the directory structure of the demonstration project. All future lessons will be demonstrated based on this directory structure.

The directory structure of my demonstration project is as follows:

gotour
├── ch01
│   └── main.go
├── ch02
│   └── main.go
└── go.mod

The root directory of the demo project is called “gotour”, where all Go language commands will be executed, such as “go run”.

The directories like ch01, ch02 are named according to the lesson, with each lesson having its corresponding directory, making it easy to find the corresponding source code. The specific Go language source code will be stored in the corresponding lesson directory.

Basic Types #

Every programming language has its own set of basic types, which correspond to real-world entities. For example, integers correspond to numbers like 1, 2, 3, 100, and floating-point numbers correspond to decimals like 1.1, 3.4, etc. Go language is no exception - it also has its own rich set of basic types, including integers, floating-point numbers, booleans, and strings. Let me introduce them to you in detail.

Integers #

In Go language, integers are divided into:

  • Signed Integers: such as int, int8, int16, int32, and int64.
  • Unsigned Integers: such as uint, uint8, uint16, uint32, and uint64.

The difference between them is that signed integers can represent negative numbers, zero, and positive numbers, while unsigned integers can only represent zero and positive numbers.

In addition to integers represented by “bit” size, there are also int and uint, which are integral types without specific bit sizes. Their sizes could be 32-bit or 64-bit depending on the CPU of the hardware device.

In the case of integers, if the bit size of int can be determined, it is recommended to choose a more specific int type, as this will make your program highly portable.

In Go language, there is also a byte type, which is equivalent to the uint8 type. It can be understood as an alias for the uint8 type and is used to define a byte. Therefore, the byte type is also considered an integral type.

Floating-Point Numbers #

Floating-point numbers represent decimals in the real world. Go language provides two precision levels of floating-point numbers: float32 and float64. The most commonly used one in projects is float64 because it has higher precision and results in smaller errors compared to float32.

The following code example defines two variables, f32 and f64, of type float32 and float64 respectively.

ch02/main.go

var f32 float32 = 2.2

var f64 float64 = 10.3456

fmt.Println("f32 is", f32, ", f64 is", f64)

Running this program will produce the following result:

$ go run ch02/main.go

f32 is 2.2, f64 is 10.3456

Note: When demonstrating examples, I will try to provide the core code needed for the example, which means that I may omit the package and main function. Unless otherwise specified, they should be placed in the main function and can be directly run.

Booleans #

A boolean type has only two possible values: true and false, which represent “yes” and “no” in the real world. They are often used in conditions such as if statements (which will be explained in later lessons). In Go language, the boolean type is defined using the keyword bool.

The following code declares two variables. You can run it yourself to see the output.

ch02/main.go

var bf bool = false

var bt bool = true

fmt.Println("bf is", bf, ", bt is", bt)

Boolean values can be used with unary operator !, which represents logical NOT, and with binary operators &&, ||, which represent logical AND and logical OR, respectively.

Strings #

Strings in Go language can represent any data. For example, the following code declares strings using the string type:

ch02/main.go

var s1 string = "Hello"

var s2 string = "世界"

fmt.Println("s1 is", s1, ", s2 is", s2)

When you run the program, you will see the printed string output.

In Go language, you can concatenate strings using the + operator to form a new string. For example, concatenating s1 and s2 mentioned above can be done as follows:

ch02/main.go

fmt.Println("s1 + s2 =", s1+s2)

Since s1 represents the string “Hello” and s2 represents the string “世界”, when you input go run ch02/main.go in the terminal, you will see the concatenated result “Hello世界” printed, as shown in the following code:

s1 + s2 = Hello世界

Strings can also be manipulated using the += operator. You can try s1 += s2 to see what new string you will get.

Zero Values #

Zero value refers to the default value of a variable. In Go language, if we declare a variable but fail to initialize it, Go language will automatically initialize its value to the corresponding zero value of its type. For example, the zero value of numeric types is 0, boolean type is false, string type is an empty string “”.

The following code example can verify these zero values for basic types:

ch02/main.go

var zi int

var zf float64

var zb bool

var zs string

fmt.Println(zi, zf, zb, zs)

Variables #

Short Variable Declaration #

Did you notice that the examples above all have a var keyword, but writing code in this way is cumbersome. With type inference, Go language provides a short variable declaration :=, as shown below:

variableName := expression

With Go language’s short variable declaration feature, variable declaration becomes very concise. For example, the variables in the above examples can be declared using the following code:

i := 10

bf := false

s1 := "Hello"

In actual project practice, if you can initialize the declared variables, then choose the short variable declaration method, which is also the most commonly used method.

Pointers #

In Go language, a pointer corresponds to the memory address where a variable is stored, which means the value of a pointer is the memory address of the variable. The & operator can be used to obtain the address of a variable, which is a pointer.

In the following code, pi is a pointer to the variable i. To obtain the value of the variable pointed to by pi, you can use the *pi expression. Try running this program and you will see that the output is the same as the value of the variable i.

pi := &i

fmt.Println(*pi)

Assignment #

When I talked about variables, I mentioned that variables can be modified, but how do we modify them? This is what an assignment statement does. The most commonly used and simplest assignment statement is =, as shown in the following code:

i = 20

fmt.Println("New value of i is", i)

In this way, the variable i is modified and its new value is 20.

Constants #

Just like variables, constants also exist in programming languages, and Go language is no exception. In a program, the value of a constant is determined during compile-time and cannot be modified once determined, which can prevent malicious tampering during run-time.

Constant Declaration #

The syntax for declaring constants is similar to that for declaring variables, except that the const keyword is used.

The following example defines a constant name with the value “飞雪无情” (“Fei Xue Wu Qing” in English). Because Go language can perform type inference, the type can be omitted when declaring a constant.

ch02/main.go

const name = "飞雪无情"

In Go language, only basic types such as boolean, string, and numeric types are allowed to be constants.

Iota #

Iota is a constant generator that can be used to initialize similar rules of constants to avoid redundant initialization. Suppose we want to define four constants one, two, three, and four, with values 1, 2, 3, and 4, respectively. If iota is not used, we need to define them as follows:

const(
    one = 1
    two = 2
    three = 3
    four = 4
)

All of the above declarations need to be initialized, which can be cumbersome because these constants follow a pattern (consecutive numbers). Therefore, we can use “iota” to declare them, as shown below:

const(
    one = iota+1
    two
    three
    four
)

fmt.Println(one,two,three,four)

If you run the program, you will find that the printed values are the same as the ones that were initialized earlier, which are 1, 2, 3, and 4.

The initial value of “iota” is 0, and its ability is to increment by 1 after each constant declaration line. Let me break down the constants above:

  1. one=(0)+1: At this point, the value of “iota” is 0, so after the calculation, the value of “one” becomes 1.
  2. two=(0+1)+1: The value of “iota” is incremented by 1 and becomes 1. After the calculation, the value of “two” becomes 2.
  3. three=(0+1+1)+1: The value of “iota” is incremented by 1 and becomes 2. After the calculation, the value of “three” becomes 3.
  4. four=(0+1+1+1)+1: The value of “iota” continues to be incremented by 1 and becomes 3. After the calculation, the value of “four” becomes 4.

If you define more constants, the pattern continues. The expression inside the parentheses represents the process of “iota” incrementing by 1.

Strings #

Strings are commonly used types in Go. In the previous section on basic types, we have already introduced strings in a basic way. In this section, I will provide a more detailed explanation of how strings are used.

Conversion Between Strings and Numbers #

Go is a strongly typed language, which means that variables of different types cannot be used or calculated together. This is to ensure the robustness of Go programs. Therefore, before assigning or calculating variables of different types, type conversion needs to be performed. There are many topics related to type conversion, and I will start by introducing the conversion between these basic types. More complex topics will be covered in the future lessons.

Taking the most common case of converting between strings and numbers as an example, the code below shows how to accomplish it:

ch02/main.go

i2s := strconv.Itoa(i)

s2i, err := strconv.Atoi(i2s)

fmt.Println(i2s, s2i, err)

The strconv package provides the Itoa function to convert an int type to a string, and the Atoi function is used to convert a string to an int.

Similarly, for floating-point numbers and boolean values, Go provides strconv.ParseFloat, strconv.ParseBool, strconv.FormatFloat, and strconv.FormatBool functions to perform the conversion. You can try them out yourself.

For converting between different numeric types, it can be done using type coercion, as shown in the following code:

i2f := float64(i)

f2i := int(f64)

fmt.Println(i2f, f2i)

This type of conversion is done using the format “type(variable to be converted)”. Using type coercion to convert numeric types may result in some precision loss. For example, when converting a floating-point number to an integer, the decimal part will be completely lost. You can run the above examples to verify the results.

After converting a variable to the corresponding type, you can perform various expression calculations and assignments on variables of the same type.

Strings Package #

When it comes to basic types, especially strings, we have to mention a standard package provided by the Go SDK called strings. It is a utility package for manipulating strings, with many useful functions that help us operate on strings, such as searching for a substring, removing whitespace from a string, splitting a string, and checking whether a string has a certain prefix or suffix. Mastering this package will benefit our efficient programming.

The following code includes some examples I wrote using the strings package. You can write your own examples according to the strings documentation and practice using them.

ch02/main.go

// Check if the prefix of s1 is "H"
fmt.Println(strings.HasPrefix(s1, "H"))

// Find the string "o" in s1
fmt.Println(strings.Index(s1, "o"))

// Convert s1 to uppercase
fmt.Println(strings.ToUpper(s1))

Summary #

In this lesson, I explained variable and constant declarations and initialization, as well as the short variable declaration. I also introduced the commonly used basic types, conversions between numbers and strings, and the usage of the strings package. With these, you can write more powerful programs.

There is one more basic type that has not been discussed in the basic types section, which is complex numbers. It is not commonly used, so I’ll leave it for you to explore. Here’s a hint: complex numbers are created using the built-in function complex.

The question for you to ponder on in this lesson is: How can you check if a certain substring exists in a string? Here’s a hint: There is a ready-to-use function in the Go standard strings package.