Introduction
In 2007, three great engineers – Robert Griesemer, Rob Pike and Ken Thompson came together and created GO language. They took the advantageous features from C, Python and Java, combined all of them in to GO to develop scalable systems. Below are the salient features of GO. Taking up a Golang course will also help you learn more.
- Strong and Simple Type System
- Lightning Fast Compiler
- Built-in Concurrency Support
- Supports Garbage Collection
Environment Setup
Download your operating system specific binary from https://golang.org/dl/
Follow the corresponding installation instruction from https://golang.org/doc/install
Typical program structure
A typical GO programs consists of the below high-level elements:
package <package_name>
import “<package_name>”
func main() {
//executable code
}
Go programs are organized as packages. Hence, the package name should be defined.
Import statements facilitate to use of external code.
The Main is the entry point. The program execution starts from here.
Variables
Variable is used to store data in memory in Go. Go being a statically typed language, every variable must be assigned a type (more details on type in next section). The type cannot be changed once assigned. The type can be in one of the following ways:
- Explicitly – by mentioning the type in the variable declaration.
- Implicitly – Leveraging compiler’s feature to infer the type based on the value assigned to the variable.
Below are the rules to be followed to construct valid variable names.
- It can consist of alphanumeric and underscore.
- It must start with an alphabet or an underscore.
- It is case-sensitive i.e., uppercase and lowercase letters are treated differently.
Variable Definition, Declaration and Initialization
In GO, the variable definition means to mention the name of one or more variables and the type of those variables. The type can be either GO built-in types or user-defined type. Below is the general syntax of variable declaration.
var comma_separated_list_of_variable_names data_type;
Note: data_type is not mandatory as GO compiler infers it based on the value assigned to the variable.
Below are some examples of valid definitions
var l, m, n int;
var binary byte;
var temperature float32;
Shown below is the syntax to assign an initial value to the variable
name_of_variable = initial_value;
ex: l = 5;
Explicit Type Declaration
In this type of declaration, the variable type is explicitly specified as part of the variable definition.
ex: var temperature float32
temperature = 45.0
Implicit Type Declaration
In this type of declaration, the variable type is not specified in the variable definition. The compiler infers the type based on the value assigned.
Below is the syntax:
variable_name := initial_value
ex: salary := 100
Data Types
This section covers the built-in data types supported in Go. The data type is a classification that specifies the kind of value a variable holds. Based, on the data type of variable, the compiler decides how much memory space to allocate and how to interpret the binary content of the value stored in the variable.
Go provides the following categories of primitive data types.
- Boolean
- Numeric
- Integer
- Float Point
- Others
- String
Below table lists the purpose of each data type and the range of value that can be stored in them.
Type | Description | Range |
Boolean | Used to store Boolean values – true or false | Not Applicable. |
Integer: uint8 | Unsigned 8-bit integers | 0 to 255 |
Integer: uint16 | Unsigned 32-bit integers | 0 to 65535 |
Integer: uint32 | Unsigned 32-bit integers | 0 to 4294967295 |
Integer: unit64 | Unsigned 64-bit integers | 0 to 18446744073709551615 |
Integer: int8 | Signed 8-bit integers | -128 to 127 |
Integer: int16 | Signed 16-bit integers | -32768 to 32767 |
Integer: int32 | Signed 32-bit integers | -2147483648 to 2147483647 |
Integer: int64 | Singed 64-bit integers | -9223372036854775808 to 9223372036854775807 |
Float: float32 | IEEE-754 32-bit floating-point numbers | |
Float: float64 | IEEE-754 64-bit floating-point numbers | |
Float: complex64 | Complex numbers with float32 real and imaginary parts | |
Float: complex128 | Complex numbers with float64 real and imaginary parts | |
Others: byte | Alias for uint8 | |
Others: rune | Alias for int32 | |
Others: uint | Either 32 or 64 bits | |
Others: uintptr | an unsigned integer large enough to store the uninterpreted bits of a pointer value | |
Others: int | Same size as uint |
Operators
An operator is a programming construct to instruct the computer to process the variables/operands to achieve the desired goal like adding two numbers, evaluating an expression and comparing it to true or false etc.
GO provides the below built-in rich set of operators.
- Arithmetic Operators
- Relational Operators
- Logical Operators
- Bitwise Operators
- Assignment Operators
- Miscellaneous Operators
Arithmetic Operators: Below table lists the arithmetic operators supported in GO.
Operator | Description |
+ | This operator performs the sum of two operands by adding them. |
– | This operator finds the difference between the two operands. It subtracts the second from the first operand. |
* | This operator finds the product of two operands by multiplying them. |
/ | This operator performs the integer division of two operands. It yields a quotient that will be of type integer. |
% | This is known as the Modulus operator. It is used to find the integer remainder of two operands. |
++ | This is a unary increment operator. It is used to increase the integer value by one. |
— | This is a unary decrement operator. It is used to reduce the integer value by one. |
Relational Operators: Below table lists the relational operators supported in GO.
Operator | Description |
== | This is the equality operator that will be used to find if two values are equal. |
!= | This is the inequality operator that will be used to confirm that two values are not equal. |
> | This is the greater than operator that will be used to check if one operand is higher than the other operand. |
< | This is the less-than operator that will be used to check if one operand is lower than the other operand. |
>= | This is the greater than or equal to operator that will be used to check if one operand is higher than or equal to the other operand. |
<= | This is the less than or equal to the operator that will be used to check if one operand is lower than or equal to the other operand. |
Logical Operators: Below table lists the logical operators supported in GO.
Operator | Description |
&& | This is the Logical AND operator that applies to boolean operands. It evaluates to true only when both the operands are true. When the left operand is false, the right operand is not evaluated. This is known as short-circuiting. |
|| | This is the Logical OR operator that applies to boolean operands. It evaluates to true when either one of the operands(s) is/are true, false otherwise. |
! | This is the Logical NOT Operator. It is used to negate the value stored in the operand i.e., if the value stored in operand is true, applying this operator, results in false and vice-versa. |
Bitwise Operators: Below table lists the bitwise operators supported in GO.
Operator | Description |
& | This is Binary AND Operator. It is applied to the binary representation of an integer. It evaluates from right to left. It evaluates to one if a bit in the respective position of both the operands is one else evaluates to zero. |
| | This is a Binary OR Operator. It is applied to the binary representation of an integer. It evaluates from right to left. It evaluates to zero if a bit in the respective positions of both the operands is zero else evaluates to one. |
^ | This is Binary XOR Operator. It is applied to the binary representation of an integer. It evaluates from right to left. It is evaluated to one if a bit in the respective positions of both the operands is different else evaluates to zero. |
<< | This is the Binary Left Shift Operator. The left operands value is shifted to the left by the number of bits specified in the right operand. This is effectively multiplying the number in the left operand by power(2, n), where n is the value in the right operand. |
>> | This is the Binary Right Shift Operator. The left operands value is shifted to the right by the number of bits specified by the right operand. This is effectively dividing the number in the left operand by power(2,n) where n is the value in the right operand. |
Assignment Operators: Below table lists the assignment operators supported in GO.
Operator | Description |
= | This is the assignment operator. It is used to assign value to a variable. |
+= | This is shortcut for adding value to current content of the variable and assigns the resultant value to the variable. |
-= | This is a shortcut for subtracting value from the current content of the variable and assigns the resultant value to the variable. |
*= | This is a shortcut for multiplying value with the current content of the variable and assigns the resultant value to the variable. |
/= | This is the shortcut for dividing value from the current content of the variable and assigns the resultant value to the variable. |
%= | This is the shortcut for taking modulus value from the current content of the variable and assigns the resultant value to the variable. |
<<= | This is the shortcut for the left shifting the current content of the variable and assigns the resultant value to the variable. |
>>= | This is a shortcut for right shifting the current content of the variable and assigns the resultant value to the variable. |
&= | This is shortcut for doing bitwise AND of current content in the variable with the value in the right operand and assigns the resultant value to the variable. |
^= | This is a shortcut for doing bitwise XOR of current content in the variable with the value in the right operand and assigns the resultant value to the variable. |
|= | This is shortcut for doing bitwise OR of current content in the variable with the value in the right operand and assigns the resultant value to the variable. |
Operator Precedence and Associativity: This determines how the operators are associated with each other in an expression and evaluated in the order of their priority. In the below table, operators are listed in the descending order of their priority.
Category | Operator(s) | Associativity |
Postfix | () [] -> . ++ – – | Left to right |
Unary | + – ! ~ ++ – – (type)* & sizeof | Right to left |
Multiplicative | * / % | Left to right |
Additive | + – | Left to right |
Shift | << >> | Left to right |
Relational | < <= > >= | Left to right |
Equality | == != | Left to right |
Bitwise AND | & | Left to right |
Bitwise XOR | ^ | Left to right |
Bitwise OR | | | Left to right |
Logical AND | && | Left to right |
Logical OR | || | Left to right |
Assignment | = += -= *= /= %=>>= <<= &= ^= |= | Right to left |
Comma | , | Left to right |
Decision Control Instructions
Decision control instructions also known as branching constructs are an important component of any program. It facilitates the addition of intelligence to the program. It allows the program to perform a different set of actions based on the state – result of evaluating an expression. Branching constructs consist of multiple conditions and a statement or block of statements associated with each condition. At any time, one of the conditions evaluates to true and statement(s) associated with that condition will be executed.
Below sections briefs each of the branching construct supported in Go programming.
If
An if statement has a Boolean expression associated with a statement or a set of statements.
Syntax:
if(booleanexpression){
/* statement(s) to execute */
}
How it works: First the Boolean expression is evaluated. Only if it evaluates to true, the statement(s) within the curly braces will be executed.
Example:
package main
import "fmt"
func main() {
var score int = 10
/* evaluate the condition */
if( score < 35 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: Fail\n" )
}
fmt.Printf("score: %d\n", score)
}
Compiling and executing the above code, gives the below result
Grade: Fail
Score: 10
If…else
Else block can follow an if statement. The code in the else block executes when the condition in the if statement evaluates to false.
Syntax:
Syntax:
if(booleanexpression){
/* statement(s) to execute */
} else {
/* statement(s) to execute *
}
Example:
package main
import "fmt"
func main() {
var score int = 40
/* evaluate the condition */
if( score < 35 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: Fail\n" )
} else {
/* execute below code if condition is true */
fmt.Printf("Grade: Pass\n" )
}
fmt.Printf("score: %d\n", score)
}
Compiling and executing the above code, gives the below result
Grade: Pass
Score: 40
if…else if…else
This construct is used to determine a single condition that will be true when several possibilities exist. In this construct, an if statement is followed by one or more else if statements and zero or one else statement.
Syntax:
if(booleanexpression_1){
/* statement(s) to execute when booleanexpression_1 is true */
} else if(booleanexpression_2) {
/* statement(s) to execute when booleanexpression_2 is true */
} else if(booleanexpression_3) {
/* statement(s) to execute when booleanexpression_3 is true */
} else {
/* statement(s) to execute when all above conditions are false */
}
Example:
package main
import "fmt"
func main() {
var score int = 30
/* evaluate the condition */
if( score >= 70 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: Distinction\n" )
} else if ( score >= 60 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: First Class\n" )
} else {
/* execute below code if condition is true */
fmt.Printf("Grade: Fail\n" )
}
fmt.Printf("score: %d\n", score)
}
Compiling and executing the above code, gives the below result
Grade: Fail
Score: 30
Nested if
This constructs allows to add if, if-else block within the if block or the within the else block or both.
Syntax:
if(booleanexpression){
if(Booleanexpression1){
/* statement(s) to execute */
} else {
/* statement(s) to execute */
}
} else {
if(Booleanexpression2){
/* statement(s) to execute */
} else {
/* statement(s) to execute */
}
}
Example:
package main
import "fmt"
func main() {
var score int = 65
/* evaluate the condition */
if( score >= 30 ) {
if ( score >= 70 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: Distinction\n" )
} else if ( score >= 60 ) {
/* execute below code if condition is true */
fmt.Printf("Grade: First Class\n" )
} else {
/* execute below code if condition is true */
fmt.Printf("Grade: Second Class\n" )
}
} else {
/* execute below code if condition is true */
fmt.Printf("Grade: Fail\n" )
}
fmt.Printf("score: %d\n", score)
}
Compiling and executing the above code, gives the below result
Grade: First Class
Score: 65
Switch
This control statement is a neater form of if…else if…. Else conditional instruction. This allows making a decision from a number of choices by comparing the content of a variable against a set of values possible for that variable.
Go supports the following types of switch statements:
Expression Switch – In this, case expression is compared against switch expression value.
Type Switch – In this, case type is compared against type of a specially annotated switch expression.
Expression switch:
Syntax:
switch (Boolean-expression | integer-expression){
case Boolean-expr1 | integer-value1:
statement(s);
case Boolean-expr2 | integer-value2:
statement(s);
case Boolean-expr3 | integer-value3:
statement(s);
……..
……..
/* there can be multiple case statements */
default : /* Optional */
statement(s);
}
Example:
package main
import "fmt"
func main() {
var score int = 90
var result string = “D”
switch score {
case 100: result = “A+”
case 90: result = “A”
case 80: result = “B”
case 70,60: result = “C”
default: result = “D”
}
fmt.Printf("Result : %s\n", result)
}
Compiling and executing the above code, gives the below result
Result: A
Type Switch:
Syntax:
switch x.(type){
case type1:
statement(s);
case type2:
statement(s);
……..
……..
/* there can be multiple case statements */
default : /* Optional */
statement(s);
}
Example:
package main
import "fmt"
func main() {
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf("type of x :%T",i)
case int:
fmt.Printf("x is int")
case float64:
fmt.Printf("x is float64")
case func(int) float64:
fmt.Printf("x is func(int)")
case bool, string:
fmt.Printf("x is bool or string")
default:
fmt.Printf("don't know the type")
}
}
Compiling and executing the above code gives the below result:
type of x :<nil>
Functions
A function is a self-contained code block that performs a coherent task. It acts as a black-box by accepting inputs optionally and providing an output that is again optional.
Every Go program contains main() function by default.
Declaring a function means writing the function signature consisting of the function name, return type and parameters. Function definition comprises implementing the code in the function body that does the actual work.
Function components and it’s meaning is as below:
func functionname( [parameters] ) [return value with it’s type] 🡺 function-header
{
Function body
}
func: This is the keyword beginning the function declaration.
Function name: Name given to identify the function
Parameters: They are the inputs passed to the function. Each parameter is associated with a type.
The function can take zero or more parameters.
Return value and type: Function may return a value or a list of values. The return type is associated with a type. The return value is optional. Some functions generate result as a effect of processing while some just change the state without generating any result.
Function Body: This is the work-horse of the function. It is the set of statements that does the actual processing and defines the work done.
Below is an example of a function called sum(). It takes two inputs number1 and number2 and return the value obtained by adding them.
func sum(number1, number2 int) int {
result int
result = number1 + number2
return result
}
Function call: The function calls another function. First is also known as the calling function while the latter is also known as called function. The calling function passes the required values in relevant order to the called function. Upon completion of the called function processing, it returns control to the called function.
Shown below is an example
package main
import "fmt"
func main() {
var number1 int = 5
var number2 int = 30
var result int
result = sum(number1, number2)
fmt.Printf( "Sum is : %d\n", result)
}
func sum(n1, n2 int) int {
var result int
result = n1 + n2
return result
}
Compiling and executing the above code gives below output
Sum is: 35
Formal Parameters and Arguments: The parameters in the function header are known as formal parameters. The actual values passed from the calling function are known as arguments. The formal parameters are local to the function.
Following are the two different ways of calling function
Call by value: In this approach, the actual values/arguments are copied into the formal parameters of the function. So any changes to formal parameters within the function will have no effect on the arguments passed to the function. This is the default mode in GO.
Call by reference: In this approach, the address of arguments are copied to the format parameter. So, any changes to formal parameters are reflected in the arguments as they are accessed by address within the function.
Arrays
An array is the data structure that is a fixed-size continuous collection of homogenous elements i.e., all elements are of identical data type.
Arrays are used to store collection of homogenous elements by declaring one array variable like student and use student[0], student[1], ……. ,student[n-1] instead declaring several individual variables like student1, student2, ….. , student
Arrays are subscript based data structure. The elements are accessed using subscript or index. Array index value starts from 0.
The below diagram is a pictorial representation of an array.
Array Declaration : Declaring an array means to mention the element type and the number of elements the array should store. Below is the syntax for declaring a one-dimensional array:
var var_name [array_size] var_type
array_size 🡺 must be an integer value greater than zero
var_type 🡺 any valid GO data type
Below code declares a one-dimensional array with 5 elements called scores of type int
var scores [5] int
Array Initialization :
Following are the direct ways to initialize array
Initialize a single array element :
Syntax: array_name[index] = value
The above syntax implies the specified value is assigned to the array element at mentioned index. Arrays being zero-based, 0 is the first element index/base index and the last element index is array_size – 1.
Ex: score[3] = 69
Initialize all the array elements:
Method 1:
Syntax: var array_name = [array_size] type {value0, value1, …… , valuearray_size-1}
The number of values must not exceed the array_size
Ex: var scores = [4]int{57,39,89,95}
Method 2:
Syntax: var array_name = [] type {value0, value1, …… , valuen}
Ex: var scores = []int{57,39,89,95}
In this case, array_size is sufficient enough to hold all the values with {}
Accessing Array Elements
Arrays being subscript based data structures, it’s elements are accessed by using index of the element along with the array name.
Syntax: array_name[index]
Ex: int score = scores[2]
In the above example, an element at index 2 from scores array is assigned to the score variable.
Below is the example which demo’s array declaration, assignment and accessing array elements.
package main
import "fmt"
func main() {
var scores [5]int /* scores is an array of 5 integers */
var len, len1 int
/* initialize elements of array scores*/
for len = 0; len < 5; len++ {
scores[len] = len + 100
}
/* output each array element's value */
for len1 = 0; len1 < 5; len++ {
fmt.Printf("Score[%d] = %d\n", len1, scores[len1] )
}
}
Compiling and executing above code gives below output
Scores[0] = 100
Scores[1] = 101
Scores[2] = 102
Scores[3] = 103
Scores[4] = 104