The Simple Golang Tutorial Part 2 - Variables, Types, and Operators
Tags: go
Published: 2021-04-12 05:20:46

Welcome back to the Golang series. Let's try to get a good understanding of how to declare and use variables, working with the types available and the operators you can use on variables in Golang.

## Variables

We will start with variables. Recall that in the previous article, we saw that the `:=` operator both declares and assigns the variable a value. Well, did you know that it is possible to split these operations into two by declaring a variable by itself and also performing the assignment in another statement?

To declare a variable, all we have to do is prefix it with `var`:

```go
var foo
foo = 3
```

We can also see that assignment here is, as in many other languages, done with the `=` operator. We will see more about this in the operators section.

Notice how there is no semicolon on either of these two lines. In Go, the semicolon syntax construct exists, but it can be omitted most of the time.

So that's it for declaring variables. Let's move on to the next important subject: types.

## Types

If you look carefully at the code snippet above, you can see that we assign a number to `foo`. Indeed, the "3" is an integer type, one of several types available in Golang.

A non-exhaustive list of basic types are enumerated below:

### Several signed and unsigned integer types

*Signed* is just a fancy way of saying that the number can represent negative integers. An unsigned type uses the bits usually used to store the sign bit to store more bits of positive numbers. This means unsigned types have a higher range of positive numbers but cannot represent negative numbers.

Golang has two generic signed and unsigned integer types: `uint` is the unsigned integer, and `int` is the signed integer type. The Golang compiler determines these variables' size, but usually, they are 32 or 64 bits long.

There are also fixed-width integer types that have the same size no matter what the compiler does:

- `int8` and `uint8` are 8 bits wide
- `int16` and `uint16` are 16 bits wide
- `int32` and `uint32` are 32 bits wide
- `int64` and `uint64` are 64 bits wide

Also, `byte` is an alias for `uint8`, and `rune` is an alias for `int32`.

### Floating-point and complex types

Golang also has a single-precision float type 32 bits long that can store decimal numbers and a larger 64-bit double-precision float that can hold more decimal places of number and has a much larger range than single-precision floats. Their names are as follows:

- `float32` is the 32-bit single-precision floating-point type
- `float64` is the 64-bit double-precision floating-point type

Unlike many other languages, there is a complex number type built-in. `complex64` has float32 real and imaginary parts, and `complex128` has float64 real and imaginary parts.

### Pointers

Simply put, you can make any type a pointer by putting a `*` on the left of the type name. So `int` becomes `*int`, `float64` becomes `*float64`, and so on.

There is even a pointer type called `uintptr` that doesn't actually act like a pointer, but it lets you get the bits of the pointer directly.


### Arrays

Arrays are declared differently than in most other languages. The brackets and size are to the *left* of the array name rather than on the right.

The consequence of placing it this way is that types are evaluated from left to right (instead of array braces having special precedence for some reason), and this makes it easier for you to understand the array's type:

```go
*int  /* pointer to int */
*[4]int /* pointer to an array with 4 int elements */
[4]*int /* array with 4 int pointer elements */
```

Much easier to read than `int* a[4]` or `int (* a)[4]`, right? (Unless you are used to C++ like I am).

### Structs

We can declare any structure using curly braces and the `struct` keyword like this:

```go
struct {
    x, y int
    z float32
}
```

This is a structure with two ints called `x` and `y`, and one float32 called `z`. We can also use pointers and arrays in a struct.


Also, we can put `[1234567890]` or `*` at the left of the struct to make it an array of structs or a pointer to a struct, respectively.


## Operators

We have essentially the same set of arithmetic and logical operators that other languages have, but for the sake of completeness, let's round them up here.

We have addition `+`, subtraction `-`, multiplication `*`, and division `/`. We also have modulus `%` (the remainder of divisions), equality and inequality `==` and `!=` respectively, less-than `<` and greater-than `<`, and hybrid combinations of these `<=` and `>=` for less than or equal and greater than or equal respectively.

We have logical AND and OR `&&` and `||` which help chain conditions (*we do not have a logical NOT operator*), and finally, there are the bitwise operators: logical AND, OR and XOR `&`, `|` and `^` respectively, left and right shift `<<` and `>>`, and a new bitwise operator called AND NOT `&^`. There is no bitwise NOT operator that inverts all the bits like C's `~` operator.

At this point, it will be helpful to know the operator precedence or the order in which Golang evaluates operators. Here's the list copied from its reference manual:

```
Precedence    Operator
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||
```

Be careful with this because the precedence is very different from other languages such as C/C++/Java and PHP. In particular, all the relational operators have the same priority, bitwise OR and XOR have the same precedence as addition and subtraction, and bitwise AND and shifts have the same precedence as multiply and divide.

---

That's all for this week, folks. Next week we'll be looking at functions, some relevant function statements, and some built-in functions.