Here’s how Google describes Go in its blog post: “Go attempts to combine the development speed of working in a dynamic language like Python with the performance and safety of a compiled language like C or C++. In our experiments with Go, to date, typical builds feel instantaneous; even large binaries compile in just a few seconds.” Let’s take a quick look at this powerful language.
Go is an open source concurrent programming language published by Google. It is similar to the C programming language, but it has several features that make it unique.
- Compilation of the project is so fast, it feels as if Go is an interpreted language rather than a compiled one. Programs are also easily edited or run on-the-fly.
- It has garbage-collection incorporated into it. So developers do not have to perform memory management as Go takes care of most of this work.
- It has built-in concurrency. So it can support concurrent work that requires permitting both communication and synchronisation.
- Go is a robust and statically-typed language. So several possible bugs can be detected during compilation, and resolved.
- Go has a fully working Web server as part of its standard library.
- There is no need to mess around with build configurations or make files as Go’s built-in build system is very simple.
Development environment set-up
To set up the local development environment, we need the following pre-requisites on our computer:
- Text editor: This is used to store our programs written in the Go language. Examples of a few editors are Windows Notepad, Vim or Vi. The files containing program source code are called source files. They must contain the extension .go.
- Go compiler: The source code written in files needs to be converted to a language that the CPU understands from the human readable source program. The compiler will compile the source code and convert the code into machine language, which the CPU can run as per program instructions.
1. Download the Go compiler from https://golang.org/dl/
2. The GOPATH environment variable set-up specifies the location of the current Go workspace. It is the only environment variable we need for the Go code.
The workspace can be located anywhere one wants. In my case I have used $HOME/dev.
$ mkdir $HOME/dev $ export GOPATH=$HOME/ dev
To test if everything works correctly, type the following command in a terminal:
go version
The result will display the Go version number.
Hello World: A sample Go program
A Go program basically consists of the following components:
- Package declaration
- Package import
- Functions and variables
- Statements and expressions
- Comments
In our sample program, we will try to use all the components. Since we have already created our workspace $HOME/dev, where we are going to create all our programs, let’s add the following code to any text editor:
package HelloWorld // package declaration (every GoProgram must start with it) import "fmt" //importing standard package for formatting input and output // first sample program – comment always starts with two / and it is ignored by Go Compiler func main() { fmt.Println("Hello World!!") //calling the method of the package fmt which prints line }
Let’s save it as HelloWorld.go in the workspace directory. Enter the following command in a terminal:
cd $GOPATH //change the current directory to our workspace directory go run HelloWorld.go //run the code stored in the file “HelloWorld.go”
The result will be displayed in the terminal as ‘Hello world!!’. The Go run command read the files (separated by spaces), compiled them, converted them into an executable saved in a temporary directory and then ran the program.
Data types, variables and constants
Data types are used to describe what type of data will be stored and how much space will be acquired to store that data. Go comes with several built-in data types.
Variables are used to give a name to the storage area. The name of a variable can contain letters, digits, and the underscore character. But it must start with either a letter or an underscore. Go is a case-sensitive language; therefore, upper case and lower case letters are distinct.
A variable definition is used to tell the compiler where and how much space to create for the variable. This definition is composed of a data type and contains a list of one or more variables of that type.
The syntax is var var_list optional_data_type;
Here, optional_data_type can be of any Go data type, i.e., byte, int, float32, complex64, Boolean or any user-defined object. And var_list may consist of one or more variables separated by commas.
Some valid declarations are shown here:
var i, j, k int; var a, c byte; var b, sal float32; d = 42;
Variables have two types of declarations.
1) Static type: The compiler knows about the type and name of the variable at the compilation time only.
2) Dynamic type: The compiler needs to interpret the type of variable based on the value passed to it.
Constants are basically variables whose values cannot be changed during the lifetime of the program. We can create constants in the same way we declare variables, but instead of var, we should use the const keyword.
const x string = “Hello World”
Flow control
The decision-making structure: When program execution depends on one or more conditions, then we should use decision-making structures. These enable us to evaluate the condition at the point of execution, and only execute a statement or statements if the condition is true or false.
The basic structure is shown in Figure 2.
Here is a sample program to print odd and even numbers between 1 and 50.
func main() { for i := 1; i <= 50; i++ { if i % 2 == 0 { fmt.Println(i, “even”) } else { fmt.Println(i, “odd”) } } }
Loops
When one needs to run the same code multiple times, loops come into play. These enable the program to execute the statements several times. The basic structure for loops is shown in Figure 3.
Here is the sample program to print numbers from 1 to 50.
package main import “fmt” func main() { i := 1 for i <= 50 { fmt.Println(i) i = i + 1 } }
Arrays and structures
Arrays: An array is a fixed-size sequential set of data items of the same type. To declare an array of some datatype, use the following syntax:
var array_name [SIZE] data_type //declaration of an array var y [5]int // y is an array of 5 integer data items.
Initialisation of an array can be done using a single statement as follows:
var salary = [5]float32{10000, 20000, 3400,70000,5000}
Here, the number of elements can’t be more than the size of the array. If you omit the size of the array, an array can hold as many elements as you can include. Here is the sample code that describes the use of an array in Go language:
package main import "fmt" func main() { var n [5]int /* n is an array of 10 integers */ var i,j int for i = 0; i < 5; i++ { n[i] = 10*i; // set value of an element at location i to 10*i } for j = 0; j < 10; j++ { fmt.Printf("Value at Element[%d] = %d\n", j, n[j] ) } } //Output Value at Element [0] = 0 Value at Element [1] = 10 Value at Element [2] = 20 Value at Element [3] = 30 Value at Element [4] = 40
Structures: A structure is a user defined data type, which enables us to make a set of data items of different types.
Structure definition and declaration syntax is as follows:
type struct_name struct { member member_type; member member_type; ...} //Structure definition var_name := struct_name {value1, value2...valuen} //declaration of structure variable
The member access operator (.) is used to access a member. This operator is coded between the structure variable name and the structure member variable that we want to access.
type Employee struct { ID int; Name string; Salary int; Department string; } //Employee structure definition /* Declaration of emp1 of type Employee */ var emp1 Employee /* emp1 specification */ emp1.ID = 822141; emp1. Name = "Palak"; emp1. Salary = 50000; emp1. Department = "Oracle"; emp1.ID = 822141;
Interfaces
Interfaces are nothing but a set of method declarations. To declare the interface, use the following syntax:
type interface_name interface { method_name1 [return_type] method_name2 [return_type]..}
The struct data type is used to implement the interfaces to define methods that are declared in the interfaces:
type Shape interface { area() float64 } /* define a circle */ type Circle struct { x,y,radius float64 } /* define a rectangle */ type Rectangle struct { width, height float64 } /* define a method for circle for implementation of Shape. area()*/ func(cir Circle) area() float64 { return math.Pi * cir.radius * cir.radius } /* define a method for rectangle for implementation of Shape. area()*/ func(rec Rectangle) area() float64 { return rec.width * rec.height }
Functions
A function is a collection of statements to perform a specific task. Every Go program must have at least one function, which is main(). A function is defined as follows:
func fun_name( [param list] ) [return_types] { // body of the function }
func: The func keyword is required to declare it as a function.
Func name: The name of the function.
Parameters: Used to store the value that is being passed to the function. A function may or may not contain parameters.
Return type: The list of data types of the values the function returns.
Function body: The function body contains a collection of statements that define the behaviour of the function.
Here is an example. This function is used to find the maximum number between two numbers. Here,‘Max function’ contains two parameters and, after processing, it will return the maximum number as a result.
package main import “fmt” func main() { /* local variable definition */ var num1 int = 10 var num2 int = 20 var result int /* calling a function to get max value */ result = max(num1, num2) fmt.Printf( “Maximum value is : %d\n”, result ) } /* function returning the max between two numbers */ func max(num1, num2 int) int { /* local variable declaration */ var result int if (num1 > num2) { result = num1 } else { result = num2 } return result }
Pointers
A pointer stores the address of the memory’s location. Before using pointers in a program, we have to declare them. The syntax for pointer declaration is as follows:
var pointer_name *pointer_data_type
Here, pointer_data_type is the pointer’s base type. It can be any valid Go data type. The asterisk is used to declare a variable as a pointer. Valid pointer declarations are:
var p *int /* pointer to an integer */ var f *float32 /* pointer to a float */
The actual data type for all pointers is the same, as pointers will only store the memory’s address. The difference between pointers of different data types is the data type of the variable the pointer points to.
The ‘*’and ‘&’ operators
‘*’ is used to find the value pointer variables. By dereferencing a pointer, we can access the value the pointer points to. So for ‘*x = 0’, we are storing 0 in the memory location x refers to. If we instead write ‘x = 0’, it will generate a compiler error because x is not a variable of type int, but a pointer of type *int.
‘&’ is used to find the address of a variable. ‘&x’returns a pointer to an int because x is an int. To modify the original variable, we should use ‘&x’.
Here is an example that describes the best use of the‘*’ and ‘&’operators:
package main import "fmt" func main() { var test int= 10 /* actual variable declaration */ var address *int /* pointer variable declaration */ address = &test /* store address of a in pointer variable*/ fmt.Printf("Address of test variable: %x\n", &test ) /* address stored in pointer variable */ fmt.Printf("Address stored in address variable: %x\n", address ) /* access the value using the pointer */ fmt.Printf("Value of *address variable: %d\n", *address ) } //OUTPUT Address of test variable: 10428004 Address stored in address variable: 10428004 Value of *address variable: 10
The Go command line argument
Command line arguments are a way to execute programs by passing the parameters along to the OS. Args provides access to command line arguments. Note that the first value is the path to the program, and then it will pass all the parameters to the program. os.Args[1:] holds the parameters that are being passed to the program. We can get individual parameter values by using normal indexing.
package main import “os” import “fmt” func main() { paramsWithProg := os.Args paramsWithoutProg := os.Args[1:] param := os.Args[2] fmt.Println(paramsWithProg) fmt.Println(paramsWithoutProg) fmt.Println(param)} //OUTPUT $ go build test-cmd-args.go $ ./ test-cmd-args w x y z [./test-cmd-args w x y z] [w x y z] x
Go commands
The syntax is go command [arguments].
Command | Usage |
build | Compiles packages and dependencies |
clean | Removes object files |
doc | Shows documentation for packages or symbols |
env | Prints Go environment information |
fix | Runs Go tool fixes on packages |
fmt | Runs gofmt on package sources |
generate | Generates Go files by processing the source |
get | Downloads and installs packages and dependencies |
install | Compiles and installs packages and dependencies |
list | Lists packages |
run | Compiles and runs Go programs |
test | Tests packages |
tool | Runs the specified Go tool |
version | Prints the Go version |
vet | Runs the Go tool ‘vet’ on packages |
You can use the ‘go help [command]’ for more information on any command.