Introduction
In the third part of the series, we will be covering the fundamentals for learning any programming language i.e. variables and data types. We will be covering from data types to variable declaration. We won't be seeing each and every detail related to the data types as some of them require a knowledge of loops and other topics, so that can be left for the different part.
Types in golang
In Golang there are 3 major types : Numeric, Bool and String. Further we also have specific types for the three data types like int, float, rune, byte, etc. We will first see how to declare a simple variable and then explore the data types in Golang.
var name string
This the variable declaration in Golang, we have the keyword var
similar to Javascript but we optionally have to specify the type of the variable if we are not immediately assigning/defining it a value.
To assign variable values, we can write the datatype of the assigned value but it is optional as the go compiler will know the datatype according to the assigned value. Further you cannot change the type of that variable once it is initialized.
var name string = "Gopher" OR var name string name = "Gopher" OR var name = "Gopher"
We also have const
for assigning constant values to a particular value set. You cannot change the value for a constant type, doing this will result in compile time error. An important property of const
can be noted here, if you simply declare a const
without initializing the value and try to access that constant, the go-compiler will throw an compilation error.
const name string = "David" OR const name string name = "Calvin" OR const name = "Smith"
By default, the values for string is an empty string""
, for integer and float it is 0
and for bool it is false
.
Each of these are valid declaration of variables in golang. Let's now dive into the data types and follow up with variable declaration in detail later.
Numeric | String | Bool |
---|---|---|
int | string | bool |
float | ||
complex | ||
rune | ||
byte |
Numeric
Let's first explore the numeric
data types in golang as you have guessed correctly, we have int
and float
as distinct categories but further we also have fine grained storage types for both of the types.
Integer
In integers as well we have two categories signed
and unsigned
, we can basically store only positive integers in unsigned
integers giving us an extra bit to play with.
For Integers, we have specific data storage types depending on the bits it can store like int8
for storing 8 bit integers, int16
for storing 16 bit integer value, int32
and int64
for the given number of bits in the integer. Similarly we will have these storage based integer values for unsigned integers like uint8
, uint16
, uint32
and uint64
. We can basically store double amount of positive integers in unsigned integers as uint
than in signed integers int
, this is because the most significant bit is not used as a sign bit since all values in the variable are positive and hence no sign bit is required.
var likes int = 140 fmt.Println(likes)
$ go run int.go 140
var age int8 = 140 fmt.Println("Age = ",age)
$ go run int.go # command-line-arguments .\int.go:6:9: constant 140 overflows int8
This will give us an error as 140
is above the limit for int8
. So, unless you have specific requirements as storage limitation, you should be using int
as the default data type for storing integers.
So, we need to define variables as per the limits to which we are going to use them, if you just specify int
the type will be selected based on your operating system, if it is 32bit
, it will take int32
, for 64bit
OSes it will take as int64
integer. If you define a variable with let say 16
bit storage and if it exceeds the limit for 16
bit storage, it would give a overflow limit
error.
Below are the limits for all the integer types in Golang:
uint8 -> 0 to 255 uint16 -> 0 to 65535 uint32 -> 0 to 4294967295 uint64 -> 0 to 18446744073709551615 int8 -> -128 to 127 int16 -> -32768 to 32767 int32 -> -2147483648 to 2147483647 int64 -> -9223372036854775808 to 9223372036854775807
If you want to reality check for the boundary values of this data types, you can code a program in go
as below:
- To find the maximum value of uint, we can flip all the bits in
0
to get all the set bits in the integer thus we use^
operator. - To find the maximum value for signed integers, we can right shit one bit so as to unset the sign bit.
- The minimum value for uint is the default value
0
. - The minimum value for int can be calculated by subtracting one from the negative of the max limit.
package main import ( "fmt" ) func main() { var min_uint = 0 var max_uint8 uint8 = ^uint8(0) var max_uint16 uint16 = ^uint16(0) var max_uint32 uint32 = ^uint32(0) var max_uint64 uint64 = ^uint64(0) var max_int8 int8 = int8(max_uint8>>1) var min_int8 int8 = -max_int8 - 1 var max_int16 int16 = int16(max_uint16>>1) var min_int16 int16 = -max_int16 - 1 var max_int32 int32 = int32(max_uint32>>1) var min_int32 int32 = -max_int32 - 1 var max_int64 int64 = int64(max_uint64>>1) var min_int64 int64 = -max_int64 - 1 fmt.Println("uint8 -> ", min_uint, " to ", max_uint8) fmt.Println("uint16 -> ", min_uint, " to ", max_uint16) fmt.Println("uint32 -> ", min_uint, " to ", max_uint32) fmt.Println("uint64 -> ", min_uint, " to ", max_uint64) fmt.Println("") fmt.Println("int8 -> ", min_int8, " to ", max_int8) fmt.Println("int16 -> ", min_int16, " to ", max_int16) fmt.Println("int32 -> ", min_int32, " to ", max_int32) fmt.Println("int64 -> ", min_int64, " to ", max_int64) }
This was the basic overview of Integers in Golang.
Though rune and byte are Integer aliases, we will explore them in the String section as they make a lot of sense over there.
Float
Similar to integers, we also have floats in the numeric category. A float is a numeric data type that can allow numbers with decimal values. A simple float can be of either float32
or float64
. The two types are defined as the precision of the decimal values. Obliviously, the float64
type is more precise than the counterpart and is also the default type assigned if not provided.
const percent = 30.5 fmt.Println(percent+50)
You optionally provide the float32
type to have a bit less precision than usual using the float32
keyword as follows:
const percent float32 = 46.34 fmt.Println(percent - 3.555)
The floating value precision of the float types in golang are as follows:
float32 --> -3.4e+38 to 3.4e+38. float64 --> -1.7e+308 to +1.7e+308.
As quite logical reasons, the precision is almost double in the float64
compared to float32
. If we try to add(any operation) a float64
number with a flaot32
, we get an error as performing operations on two differently stored types can't be operated.
Complex Numbers
We also have complex numbers in golang. This are the numbers which deal with a real and a imaginary numbers. We initialize the complex variable using the complex
function which takes two parameters the real
part and the imagianry
part. Both the parts or numbers are stored as float in the complex data type.
So, since golang has float32
and float64
data types, we will have complex64
and complex128
as complex types. Since we are storing two flaot64
, it has a complex128
type and complex64
for both parts as float32
. Here as well, you cannot store the two parts(real and imaginary) as different float types i.e. You need to have both real and imaginary as either flaot32
or flaot64
.
var percent = 30.738 var f = 4.545 var comp1 = complex(f, percent) var comp2 = complex(percent, f) fmt.Println(comp1 - comp2)
(-26.192999999999998+26.192999999999998i)
Golang automatically adds the i
or iota in the complex/imaginary part for better readability.
Strings
We can now move onto the string
data type in golang. It has several data types like byte
, rune
, string
. In golang, byte
and rune
store individual characters whereas string
can hold multiple characters.
Byte
A byte in golang is an unsigned 8 bit integer, which means it can hold numeric data from 0 to 255. So how is this displaying characters if it stores integer. Well, because each number it stores is mapped to the ASCII character set which is used to represent characters.
A byte can be stored in a single quote ''
, if we use double quotes""
, the variable is considered as string if we aren't specifying the data type.
const c byte = 't' fmt.Println(c)
$ go run byte.go 116
This gives the output as a number between 0 and 255 depending on the character which you have stored. To print the actual character you need to type caste into a string like:
const c byte = 't' fmt.Printf("Character = %c \nInteger value = %d\n", c, c)
$ go run byte.go Character = t Integer Value = 116
We can get the character equivalent of the byte representation number using the Printf function and the %c
place holder for a character. The \n
is used to end the line just for displaying proper output.
We can even store numbers between 0
and 255
as it is internally an uint8
.
Rune
A rune is extended type of byte as it stores int32
numbers and hence it represents Unicode
characters. This is the default type if you do not specify byte
and use single quotes to assign a character. Using rune, we can assign it an unicode characters to display some rich characters and literals like emoji or expressions.
var smiley_emoji = '\u263A' fmt.Printf("Smiley Emoji --> %c", smiley_emoji)
So, rune is pretty amazing type to play with characters in golang. As it is a default type assigned against byte if not provided while assignment.
String
Strings are basically a slice(list) of bytes. Each character in a string is a byte. By default the string will be empty if you don't initialize it with a value.
const language string language = "C++" OR const language string= "Python" OR const language = "Javascript"
We can even access particular character in the string using it's index.
const code = "12AB34CD" fmt.Println(code[6])
$ go run string.go 67
This gives us a integer as we are accessing the byte from the string using its index. Thus, we can use %c
in the Printf
function to format and print the equivalent characters of the byte.
const code = "12AB34CD" fmt.Printf("2nd Character in string = %c\n", code[4])
$ go run string.go 2nd Character in string = A
We can also declare strings using backticks/backquotes or whatever you call it (```), assigning string with this allows us to write multi line string.
var statement = `This is the first line The next line The last line` fmt.Println(statement)
$ go run str-backticks.go This is the first line The next line The last line
Further in the loop article we will see how to loop/iterate over a string.
Boolean
This type is used to store either true
or false
in golang. The default value of a boolean variable is false
.
var power bool fmt.Println(power)
$ go run bool.go false
We can assign the variable as either true
or false
.
const result = true fmt.Printf("The statement is %t", result)
$ go run bool.go The statement is true
So, using the %t
we can print the value of a boolean value in golang in the Printf
function.
Creating Variables
Now, we have familiar with data types in golang, we can more expressively create, declare, initialize variables in golang.
There are 3-4 primary ways to define a variable most of which we have already seen.
Declaring a Variable
We can declare a variable without assigning it any value but for that we need to then provide the data type, this can be done using the following command:
var expereience int expereience = 2
We can even use const
for constant value in the given scope.
Here, we can even declare multiple variables by separating each variable/constant with comma ,
which can be done as follows:
var a, b, c int OR const i, j, k bool
Defining and Initializing at the same time
We can initialize a variable/constant in golang by explicitly giving it a value. We can do that by using var
for variable value or const
for a constant value. We can optionally provide the data type at this moment as golang will automatically detect the type and assign the memory according to the value given.
var place string = "home"
Here, there is no compulsion to provide the datatype
as the compiler will be able to know it from the asisgned value. Though if you want to provide a non-default value you can specify the datatype.
Declaring Multiple Variables
We can assign multiple variables at once by separating them with comma,
. The variable name to the left and the values to the right needs to separated with comm on both sides.
var x, y, z = 100, '#', "days" fmt.Printf(" x = %d \n y = %c \n z = %s \n",x,y,z)
$ go run multiplvar.go x = 100 y = # z = daysofcode
We can are declaring and assigning multiple variables, the x
variable is assigned an integer value, y
with a rune
(by default) and z
with a string. We are using Printf
function with place holders for int %d
, rune/byte %c
and string as %s
. The \n
is for a new line.
If we want to assign the variables with a particular data type, we can use the var keyword as a list of values.
var ( x int8 = 100 y byte = '#' z = "daysofcode" ) fmt.Printf(" x = %T \n y = %T \n z = %T \n",x,y,z)
$ go run multiplvar.go x = int8 y = uint8 z = string
This is not only limited to var
we can also use const
to declare multiple constants with type constraint. Also, note we are using the %T
placeholder for getting the type of the data stored in the variable.
Also, we can define(declare and initialize) multiple variable with same data type with command separated as follows:
var pi, e, G float32 = 3.141, 2.718, 6.67e-11 var start, end byte = 65, 90 fmt.Println(pi, e, G) fmt.Printf("%c %c\n",start, end)
$ go run multp.go 3.141 2.718 6.67e-11 A Z
Assigning Variable using Walrus Operator (Shorthand Declaration)
We can skip usign var
or the datatype
by using the :=
walrus operator. This type of assignment using walruns
operator can only be allowed in the function body and not anywhere else, in the global scope this type of assignment is not allowed.
place := "school"
This is such a simple shorthand for assigning variables though only in a function body.
Also, multiple variable declaration is possible with walrus operator.
x, y, z := "foo", 32, true fmt.Println(x, y, z) fmt.Printf("%T %T %T", x, y, z)
$ go run walrus.go foo 32 true string int bool
Links to all code and links are visible on the GitHub repository.
Conclusion
So, from this part of the series, we were able to understand variables and the various data types in Golang. Though we didn't got too much in detail still we can find ourselves a bit comfortable in understanding basic go scripts. In the next section, we will looking into conditional statements and loops. This would give a good grasp on iterating over a string and even learn arrays(just the basics) we will explore Arrays and slices(remember strings?) after that.
So, if you have any questions, suggestions, or feedback please let me know in the comments or on the social handles. See you next time, Happy Coding :)