Go Programming - basics
golang
Installation - Linux
This guide/article was written for Debian 10 GNU/Linux
running latest updates. Before you begin, run following command to update your system.
#apt update && apt upgrade -y
Once you have completed above step, now it’s time to install Go Programming Language
or golang
in your Linux host.
First, you need to install a program called curl
to fetch the packages files for golang
.
apt install -y curl
Once you have installed curl
, head over to official Go downloads page) and select appropriate golang
binary release’s tarball or package.
Now download the package using curl
command.
$curl https://dl.google.com/go/go1.14.3.linux-amd64.tar.gz --output go1.14.3.linux-amd64.tar.gz
Note: You can check the downloaded package’s hashsum if you are unsure about the package you have downloaded.
Now you need to extract the contents of the golang
installation package you have downloaded.
$tar xzvf go<VERSION>.linux-amd64.tar.gz
You will have a directory called/go
in your home directory.
You will need to change the permission of the directory and it’s content to user and group root
$sudo chown root:root ./go
Move the file to /usr/local
directory. This is done to ensure the files in go
directory is available throughout the environment session.
$sudo mv go /usr/local
If you get permission errors, try following command:#tar -C /usr/local -xvzf go1.14.3.linux-amd64.tar.gz
This will extract the contents of the package into/usr/local
directory
Now, create appropriate golang
work directory in your home directory.
Edit ~/.profile
from non-root user and insert the following lines:
export GOPATH=$HOME/<GO_WORKDIR>
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
Refresh your profile by running:$source ~/.profile
Testing your installation
Now, go into the directory you have created for your golang
work, and create a directory hierarchy folder by running following command:
$mkdir -p <GOLANG_WORKDIR>/src/my-1st-project/hello
Once you have done that, you can createhello.go
file inside above directory. Open thehello.go
file using your favorite text editor and enter following code:
package main
import "fmt"
func main() {
fmt.Printf("Hello, World!\n")
}
Once you have done that, you need to compile the code by invoking go install
command.
$go install my-1st-project/hello
Now you can run the compiled program by calling hello
in your current directory. It should print out Hello World
.
Anatomy of a Go program
// this program imports fmt package and print
// "Hello, World" to the output
package main
import (
"fmt"
)
func main() {
fmt.Printf("Hello, World\n")
}
/*
This program imports fmt package and print
"Hello, World" to output
*/
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, World")
}
In above code, first few lines will be denoted for comments about the code. You can start writing comments by adding //
(double forward-slash) or by /*
(forward-slash and asterisk) and closing with */
(asterisk and forward-slash).
The package package main
has a special meaning in Go
and it will make your code compile for an executable and not the package
Next , import ( "fmt" )
imports fmt
package which does formatted printing.
Finally, its our main program code. It is started with func main()
then followed by {}
. In the {}
, we will write a function that is provided by fmt
package, that is Println
or Printf
followed by the content inside ()
.
Go tools
Golang
comes with a binary called go
. It is used for tasks such as building, testing, benchmarking, and starting third party packages and more.
Copy below code into welcome.go
.
// Print a friendly greeting
package main
import (
"fmt"
)
func main() {
fmt.Println("Welcome Gophers ☺")
}
Now, type following command to run the file.
$go run welcome.go
You should see a statement printed out with smiley face. What happens in the background is that go
interpretes the code and print the ouput.
Now, type the following command to compile the code.
$go build welcome.go
This will compilewelcome.go
file into an executable depending on your host architecture.
Go Basics
Let’s write a program that calculates the mean or average of two numbers. Following code does it.
// calculate mean of two numbers
package main
import (
"fmt"
)
func main() {
var x int
var y int
x = 1
y = 2
fmt.Printf("x=%v, type of %T\n", x, x)
fmt.Printf("x=%v, type of %T\n", y, y)
var mean int
mean = (x + y) / 2
fmt.Printf("result: %v, type of %T\n", mean, mean)
}
In above code, you declare two variables called x
and y
with int
as its variable type. By default golang
will assign value 0 to the variable until a value is assigned to it which is done in the next line, x=1
& y=1
. Following line prints the value and the type, %v
denotes value and %T
denotes the type. Then we declare a variable with type int called mean
and perform calculation for mean in the following line. Finally we print the result and it’s type.
To run the code, simply type go run <FILENAME>.go
. You should see some output. Lets examine the output.
In the output, you would have noticed that the result of mean
operation is 1 when the mathematical result is 1.5. To solve this, we will introduce float64
variable type. There is also float32
. Following code snippet will show you.
var x float64
var y float64
x = 1.0
y = 2.0
You can shorten the code above by writing the following:
var x, y float64
x, y = 1.0, 2.0
Which can be simplified by writing following:
x, y := 1.0, 2.0
This means that the variable x
and y
is created and assigned with floating point value. Golang
will automatically detect it’s variable type in runtime or during compilation.
If and Switch
if..else
Statement
package main
import "fmt"
func main() {
x := 10
if x > 5 {
fmt.Println("X is large")
}
}
In above code, we are checking if value x
is bigger than 5. Unlike Java or C, you do not need parentheses to express the condition. Now the condition is met, it will print X is large
.
Lets write a if..else
statement. Following code shows the usage of if..else
:
if x > 100 { fmt.Println("X is big") }
else { fmt.Println("X is small") }
Now if you declare a variable x
and assign a value that is lesser than 100
, the program will execute the else
statement block because it did not satisfy the condition. Next, I will introduce else if
statement.
x := 20
if x < 10 {
fmt.Println("X is lesser than 10")
} else if x < 30 {
fmt.Println("X is lesser than 30")
} else {
fmt.Println("No match")
}
In above code, we have introduced else if
. Suppose you have multiple if
conditions in which one of the condition is fulfilled, the statement block for that else if
statement will execute. So in this case, variable x
has a value of 20
. So when the code is interpreted, it will match the second if
statement, else if
because x is lesser than 30
.
switch
Statement
package main
import (
"fmt"
)
func main() {
x :=2
switch x {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
case 3:
fmt.Println("3")
default:
fmt.Println("Default")
}
}
Above code is how you write a switch
statement in golang
. You declare switch
by giving it a parameter x
and declare case 1..3
and case default
when none of the cases match. When you run the code by typing:
-$go run <FILENAME>.go
You will see that the program outputs 2
as the value stored in parameter x
matches case 2
. Now if you do not want to match any case, match the default
case, change the value of x
to zero as example snippet below:
x := 0
switch x {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
default:
fmt.Println("Default")
}
When you run above code, complete with package, imports and main function, you will observe that it outputs to default
as value x
does not match any of the case in the switch
statement. Switch statement also allows string to be used in case statement. Following code shows an example:
x := "case"
switch x {
case "case":
fmt.Println("match")
case "different":
fmt.Println("different match")
default:
fmt.Println("default")
}
As with other switch case
statements, this code block checks if the variable x
is match in the case statements. It should print out match
as it matches case case
.
You can also do the following:
x := 2
switch {
case x < 10:
fmt.Println("more than 10")
case x > 100:
fmt.Println("more than 100")
default:
fmt.Println("default")
}
In above case, you can directly assign condition to the case statement. In this code, it will execute the first case statement as it matches with the condition provided.
For loops
package main
import (
"fmt"
)
func main() {
for x := 0; x < 3; x++ {
fmt.Println(x)
}
}
Above code is one example on how you can write for
loop statement. The statement starts with variable x
which you can change, then the condition, which is x<3
, and then the increment x++
. So the code start from 0, check if 0 is lesser than 3, print the value of 0 and then increase the value of 0 by 1. Upon next execution, the same step happens, until the condition is fulfilled.
Another example:
for x := 0; x < 3; x++ {
if x > 1 {
break
}
fmt.Println(x)
}
In above code, the for loop runs until it satisfy the if
condition inside the for
loop. Once it satisfies the condition, it breaks from the loop. Therefore only value 0 and 1 will be printed.
In the next example we will look how we can use continue
to avoid printing 0 and print 1 and 2 instead.
for x := 0; x < 3; x++ {
if x < 1 {
continue
}
fmt.Println(x)
}
In this example, when the for
loop runs, it checks the if
condition, since it satisfies the condition it continues the execution without printing the value of x
.
You can also write for condition in following way:
x := 0
for x < 3 {
fmt.Println(x)
x++
}
This is like while
loop in other languages.
In final example, for
loop can also be written in following way:
x := 0
for {
if x > 2 {
break
}
fmt.Println(x)
x++
}
In above example, the for loop runs and checks the condition of if
statement, since it does not pass the condition, it prints out the value of x and increment the value of x. When it satisfies the if condition, it simply breaks from executing.
Strings
package main
import (
"fmt"
)
func main() {
string := "This is a string"
fmt.Println(string)
fmt.Println(len(string)
fmt.Printf("string[0] = %v (Type %T)", string[0], string[0])
}
In above code, we declare a variable string with the value. In the next line we simply print the content of the variable. In following line, we print the length of the string. Finally we check the first index of the string variable. print it’s value and it’s type which will be uint8
is a byte.
If you try to assign a new value to the first index, as shown below:
string[0] = 11
The go compiler will throw an error saying you cannot assign the value. This tells us that strings are immutable, that is once a string is assigned to a variable it cannot be changed.
Following code will concatenate two strings together:
fName := "Vigneshwaran"
lName := "Ravichandran"
fmt.Println(fName + " " + lName)
Unicode
Strings in golang
support unicode characters. Following example shows unicode support:
fmt.Println("This is ½")
Multiline
Following code shows how you can write multiple lines in golang
.
string := `
This is a string.
This is a second string.
`
fmt.Println(string)
This will output in a multiple line output.
Slice
To access parts of the string you can use slice. Example below shows how slicing works.
string := "This is a string"
fmt.Println(string[4:11])
fmt.Println(string[4:])
fmt.Println(string[:4])
In above code snippet, we have assigned a string to a variable and in 2nd line we slice the string from index 4 to index 10 omitting index 11. In following line, we I have specified the start index but left end index empty. This will result in the printing to start from index 4 to the end of the index. In last line we have specified the end index. So the printing will start from the start of index until the 3rd index omitting 4th index.
Slice
package main
import (
"fmt"
)
func main() {
members := []string{"Vigneshwaran", "Uthayamurthy", "Letchumi"}
fmt.Printf("members = %v (Type %T)\n", members, members)
fmt.Println(len(members))
fmt.Println(members[0])
fmt.Println(members[1:])
}
A slice a sequence of items. All items in the slice must be same type. After func main()
, we specify the type by square brackets then the type string
. Then we will the slice with curly brackets. You can use the len function to measure the length of the slice. You can also start from specific position or specify specific position of the slice. The 2nd line after slice declaration will print out the values in the slice and it’s type.
To access the elements in the slice, you can do the following:
for x := 0; x < len(members); x++ {
fmt.Printf("Member: %v\n", members[x])
}
x := 0
for x < len(members) {
if members[x] == "Uthayamurthy" {
fmt.Printf("Member found. Member Name: %v\n", members[x])
}
x++
}
for x := range members {
fmt.Println(x)
}
for x := range members {
fmt.Printf("Member Name: %s\n", members[x])
}
for index, name := range members {
fmt.Printf("Index: %d = Name: %s\n", index, name)
}
for _, name := range members {
fmt.Printf("Member Name: %s\n", name)
}
In above code snippet, you can you traditional for loop to access the slice. member[x]
will access the value in the index. You can also use range
. Using range, you will need to specify the index
and the value variable you want. Then you can access the member of the slice. To omit the index, in golang
you can use underscore _
.
To append an element into the slice, we use append
. Following example shows the usage of append
:
pets := []string{"Dog","Cat"}
pets = append(pets, "Bird")
for _, pet := range pets {
fmt.Println(pet)
}
The output of above code will include element Bird
in the slice.
Maps
credentials := map[string]string{
"username": "vgnshlvnz",
"password": "!@m@h@ck3r",
}
fmt.Println(len(credentials))
fmt.Printf("Username: %s\n", credentials["username"])
fmt.Printf("Password: %s\n", credentials["password"])
for _, value := range credentials {
fmt.Printf("Value: %s\n", value)
}
for key, value := range credentials {
fmt.Printf("%s = %s\n", key, value)
}
credentials["url"] = "https://facebook.com"
for key, value := range credentials {
fmt.Printf("%s = %s\n", key, value)
}
delete(credentials, "url")
for key, value := range credentials {
fmt.Printf("%s = %s\n", key, value)
}
In above code snippet, you declare a map
by typing out map followed by the type of the key and the type of the value. In it, you declare your key, value pairs with a comma ,
after every key,value pair including the last pair. The rest is self explanatory as you can iterate through the maps
as you would do with slices
. To add a key, value, you declare credentials[url] = "https://facebook.com"
which will add new pair to the map
. To delete, you simply call delete(credentials, "url")
. You would enter the map variable and the key you would want to delete.
Functions
Defining functions
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func divmod(a int, b int) (int, int) {
return a / b, a % b
}
func main() {
val := add(1, 3)
fmt.Println(val)
div, mod := divmod(3, 2)
fmt.Printf("div=%d, mod=%d\n", div, mod)
}
Above code shows you how to declare a function. When you declare a function, you must specify the variable type and it’s return type, as shown below:
func add(a int, b int) int
golang
can also return more than one as shown above. You need to use parenthesis when specifying multiple return types.
Parameter passing
package main
import "fmt"
func doubleAt(values []int, i int) {
values[i] *= 2
}
func double(x int) {
x *= 2
}
func doublePtr(x *int) {
*x *= 2
}
func main() {
values := []int{1, 2, 3, 4}
doubleAt(values, 2)
fmt.Println(values)
val := 10
double(val)
fmt.Println(val)
doublePtr(&val)
fmt.Println(val)
}
In above code, you pass parameters to the function to process the parameter. Take note that golang
passes by value, that whatever you pass into a function, will be applicable within the function body. To change the value, you can use go
pointers. You can declare a function like below, with pointer:
func doublePtr(x *int)
To pass the value of your variable into the function, you need to use &
like below:
doublePtr(&val)
For slices however, the value is changed even if the slice
is outside of the function.
Errors
package main
import (
"fmt"
"math"
)
func sqrt(x float64) (float64, error) {
if x < 0 {
return 0.0, fmt.Errorf("sqrt of negative value (%f)", x)
}
return math.Sqrt(x), nil
}
func main() {
s1, err := sqrt(2.0)
if err != nil {
fmt.Printf("Error: %s", err)
} else {
fmt.Println(s1)
}
s2, err := sqrt(-2.0)
if err != nil {
fmt.Printf("Error: %s", err)
} else {
fmt.Println(s2)
}
}
In above example, we declare a function to calculate the positive square root value. In the function header, we specify error
return type to catch any error. In this case, if a number is negative, then the error part of the return will be provided. In main
function, we declare a simple if..else
statement to check if the err
variable is empty. In second attempt s2
, an error will be generated since it is a negative number.
Defer
package main
import (
"fmt"
)
func cleanup(name string) {
fmt.Printf("Cleaning up %s\n", name)
}
func worker() {
defer cleanup("A")
defer cleanup("B")
fmt.Println("worker")
}
func main() {
worker()
}
Golang
has a garbage collector. Which means you don’t have to deal with memory management. When you allocate an object and then stop using it, Golang
's garbage collector will clear it up. However, memory is just one kind of resource. And you may have other resources you use in your program. For example, files, sockets, virtual machines and others. You’d like to make sure that these resources are closed when you’re done with them as well. To make sure a resource is closed, use defer.
To think of defer, think of a process you would like to do after main process, say you want to authenticate a user then redirect the user to his/her homepage. You can you defer in this case, where the main function of authenticating of users will run first before running deferred function of show his/her homepage.
Above example shows a simple usage of defer. When you execute the code, the interpreter will print the worker
print statement before calling cleanup("B")
and then cleanup("A")
.
Structs
package main
import "fmt"
type credentials struct {
Username string
Password string
isLoggedIn bool
}
func main() {
credentailOne := credentials{
"vgnshlvnz",
"!@m@h@ck3r",
false,
}
fmt.Printf("%+v\n", credentailOne)
fmt.Println(credentailOne.Username)
credentailOne.isLoggedIn = true
fmt.Println(credentailOne.isLoggedIn)
}
There are times you’d like to define your own data structures. In golang
you’ll use Struct to combine several fields into a datatype.
In example above, we defined a Struct called credentials
and set some variable and it’s datatype. Then in function main, we created an instance of the struct with our values. We printed the values of the struct, printed individual variable from the struct and then changed the value of one of the variable in the struct.
If you’re coming from languages such as Java or C++, you might wonder if you can have private or protective fields which are not exposed outside of your package. In Go, this is very simple. Everything that starts with an uppercase letter, is accessible from other packages. Otherwise, it’s accessible only from within the current package.
Methods
package main
import "fmt"
type Trade struct {
Symbol string
Volume int
Price float64
Buy bool
}
func (t *Trade) Value() float64 {
value := float64(t.Volume) * t.Price
if t.Buy {
value = -value
}
return value
}
func main() {
t := Trade{
Symbol: "MSFT",
Volume: 10,
Price: 99.98,
Buy: true,
}
fmt.Println(t.Value())
}
In above example, we have created a function called Value
which accepts pointer struct Trade
as t
with a floating point return. A calculation is performed then if t.Buy
value is true then the value is changed to negative.
# How To Install Go on Debian 10)
# Getting Started)
Written with StackEdit.