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
:
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
anduint8
are 8 bits wide -
int16
anduint16
are 16 bits wide -
int32
anduint32
are 32 bits wide -
int64
anduint64
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:
*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:
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.
Top comments (0)