GoLang - The Ultimate Guide
GoLang - The Ultimate Guide
GoLang is becoming one of the most popular languages, which means that
learning it can open up new doors of opportunity and even help you land a job at
various companies that use Go extensively.
Ease of writing concurrent programs, fast compilation, simple syntax, and static
linking are some of the features that make Go an ideal candidate for developing
various applications.
Features:
Edited by
Sufyan bin Uzayr
First edition published 2023
by CRC Press
6000 Broken Sound Parkway NW, Suite 300, Boca Raton, FL 33487-2742
and by CRC Press
4 Park Square, Milton Park, Abingdon, Oxon, OX14 4RN
CRC Press is an imprint of Taylor & Francis Group, LLC
© 2023 Sufyan bin Uzayr
Reasonable efforts have been made to publish reliable data and information, but the author and
publisher cannot assume responsibility for the validity of all materials or the consequences of their use.
The authors and publishers have attempted to trace the copyright holders of all material reproduced in
this publication and apologize to copyright holders if permission to publish in this form has not been
obtained. If any copyright material has not been acknowledged please write and let us know so we may
rectify in any future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced,
transmitted, or utilized in any form by any electronic, mechanical, or other means, now known or
hereafter invented, including photocopying, microfilming, and recording, or in any information
storage or retrieval system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, access www.copyright.com
or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923,
978-750-8400. For works that are not available on CCC please contact mpkbookspermissions@tandf.
co.uk
Trademark Notice: Product or corporate names may be trademarks or registered trademarks and are
used only for identification and explanation without intent to infringe.
DOI: 10.1201/9781003309055
Typeset in Minion
by KnowledgeWorks Global Ltd.
Contents
Acknowledgments, xix
About the Author, xxi
v
vi ◾ Contents
INSTALL Go ON WINDOWS8
How Can We Know Which Go Language Version Is
Preinstalled?9
Downloading and Installing Go9
WRITING THE FIRST Go PROGRAM10
Why Is There a “Go Language”?11
What Is Missing in Go That the Other Languages Have?11
Hardware Restrictions12
The Upsides and Downsides of the Go Language12
TERMINAL13
The Open Terminal Tool Window13
Start the New Session14
INSTALL Go ON Mac14
Making Our First Program16
Implement a Go Program16
Do Go Programs Interact with Programs Written in C/C++?17
HOW CAN WE CREATE AN EMPTY FILE IN GoLang?17
HOW TO MAKE A DIRECTORY IN Go19
HOW TO READ AND WRITE A Go PROGRAM20
HOW DO WE RENAME AND TRANSFER A FILE
IN GoLang?23
HOW TO READ A FILE LINE BY LINE AND CONVERT
IT TO A STRING24
BASIC SYNTAX25
Tokens25
Line Separator25
Comments25
Identifiers26
Keywords26
Whitespace27
DATA TYPES IN Go27
Numbers28
Contents ◾ vii
Booleans30
Strings30
VARIABLES IN Go31
Declaring a Variable32
Employing the var Keyword 32
Using the Short Variable Declaration 35
CONSTANTS38
How Should We Declare?39
Untyped and Typed Numeric Constants39
Numeric Constant 39
String Literals 41
Boolean Constant 42
VARIABLE SCOPE IN Go43
Local Variables43
Global Variables44
DECLARATION OF MULTIPLE VARIABLES46
SHORTHAND DECLARATION48
OPERATORS IN Go49
Arithmetic Operators50
Relational Operators51
Logical Operators53
Bitwise Operators53
Assignment Operators54
Misc Operators56
CONTROL STATEMENTS57
if Statement57
if…else Statement58
Nested if Statement60
if..else..if Ladder61
SWITCH STATEMENT63
Expression Switch63
Type Switch64
viii ◾ Contents
ARRAYS65
Creating and Using an Array65
Using var Keyword 65
Using a Shorthand Declaration 66
Multidimensional Array67
How Do You Copy an Array into Another Array?68
How Can We Pass an Array to a Function?69
SLICES70
Slice Declaration70
Slice Components71
How Do We Create and Begin a Slice?72
Using Slice Literal 72
Using an Array 72
Using an Existing Slice 73
Using the make() Function 74
How to Iterate over a Slice75
Using the for Loop 75
Using Range in a for Loop76
Using a Blank Identifier in a for Loop 76
Slice Composite Literal77
How to Sort a Slice of ints77
Ints 78
IntsAreSorted 78
How Do We Trim a Slice of Bytes in GoLang?79
How Do We Split a Slice of Bytes?81
STRING82
String Literals83
Using Double Quotes (“”) 83
Using Backticks(“) 83
How Do We Trim a String?84
Trim 84
TrimLeft 85
Contents ◾ ix
TrimRight 86
TrimSpace 87
TrimSuffix 88
TrimPrefix 89
How to Split a String90
Split 90
SplitAfter 91
SplitAfterN 92
MAPS93
How Do We Create and Initialize Maps?94
Simple 94
Using the make() Function 95
WHAT IS A BLANK IDENTIFIER (underscore)?96
DEFER KEYWORD97
PANIC IN GoLang98
RECOVER99
CLOSURES100
RECURSION101
POINTERS102
What Are Points Used For?102
Pointers Declaration and Initialization103
Declaring a Pointer 103
Pointer Initialization 103
Dereferencing a Pointer104
In GoLang, How Can We Instantiate a Struct Using the
New Keyword?105
Pointers to a Function106
Create a Pointer and Pass It to the Function 106
Passing an Address of the Variable to Function Call 107
Pointer to a Struct108
Pointer to Pointer in Go109
How to Declare a Pointer to a Pointer 109
x ◾ Contents
Comparing Pointers110
== operator 110
!= operator 111
GoLang STRUCTURES112
Pointers to a Struct114
GoLang’s NESTED STRUCTURE114
GoLang METHODS115
Method with the Struct Type Receiver116
Method with the Non-Struct Type Receiver116
Methods with the Pointer Receiver117
INTERFACES118
How Do We Make an Interface?119
How to Implement Interfaces119
Why Are Go Interfaces Wonderful?120
Redundant Functions 120
INHERITANCE121
POLYMORPHISM USING INTERFACES123
Init Function166
Important Considerations167
Giving the Packages Names169
Code Exported170
Essential Go Packages and Libraries172
Awesome Go172
GoLang-Set 172
Color 174
Now 175
Gen 176
Gorm 178
Goose 180
Glide 180
Ginkgo 181
Etcd 181
NSQ 182
Docker 184
Kubernetes 184
DEPENDENCY MANAGEMENT184
Versioning184
Modules185
Installing Dependencies186
Dependencies Must Authenticate187
Remove Unused Dependencies187
Installing Dependencies That Are Missing188
Updating the Versions of Dependencies188
Listing Dependencies190
Module vs. Package190
Naming190
Fetching Packages191
Contents ◾ xiii
Booleans 224
Strings 225
Type Conversion226
Type Assertion226
Structs228
Initializing230
Composition vs. Inheritance230
HOW DO YOU MAKE MODULES IN GoLang?235
Adding Dependencies to the Go Module237
PACKAGE MANAGEMENT USING Go MODULES237
What Exactly Is the Go Module?238
Starting Out239
Module Initializing 239
Setting Up Dependencies 239
Eliminating Unnecessary Dependencies 239
Updating a Dependency Version240
ERROR HANDLING240
Error Type Representation241
Various Approaches to Getting More Information
from an Error242
Don’t Ignore Errors246
IN GoLang, THERE ARE SEVERAL TECHNIQUES
TO COMPARE STRINGS247
Making Use of Comparison Operators247
Using the Compare() Method249
FUNCTIONS IN Go250
Function Declaration250
Function Calling251
Function Arguments252
FUNCTION RETURNING MULTIPLE VALUES253
Giving Names to the Return Values254
VARIADIC FUNCTIONS255
Contents ◾ xv
ANONYMOUS FUNCTION256
GoLang main AND init FUNCTIONS256
main() Function257
init() Function257
APPRAISAL, 303
BIBLIOGRAPHY, 329
INDEX, 333
Acknowledgments
There are many people who deserve to be on this page, for this book would
not have come into existence without their support. That said, some names
deserve a special mention, and I am genuinely grateful to:
xix
About the Author
Sufyan bin Uzayr is a writer, coder, and entrepreneur with over a decade
of experience in the industry. He has authored several books in the past, per-
taining to a diverse range of topics, ranging from History to Computers/IT.
Sufyan is the Director of Parakozm, a multinational IT company spe-
cializing in EdTech solutions. He also runs Zeba Academy, an online
learning and teaching vertical with a focus on STEM fields.
Sufyan specializes in a wide variety of technologies, such as JavaScript,
Dart, WordPress, Drupal, Linux, and Python. He holds multiple degrees,
including ones in Management, IT, Literature, and Political Science.
Sufyan is a digital nomad, dividing his time between four countries. He
has lived and taught in universities and educational institutions around
the globe. Sufyan takes a keen interest in technology, politics, literature,
history, and sports, and in his spare time, he enjoys teaching coding and
English to young students.
Learn more at sufyanism.com.
xxi
Chapter 1
IN THIS CHAPTER
➢➢ What is GoLang?
➢➢ Major concepts
➢➢ Advantages and disadvantages
➢➢ Syntax and code basics
➢➢ Additional info
DOI: 10.1201/9781003309055-1 1
2 ◾ GoLang: The Ultimate Guide
IS IT REFERRED TO AS Go OR GoLang?
Is the language known as Go or GoLang? Google takes it from the horse’s
mouth: the language is called “Go.”
According to Google, the name “GoLang” originates from the URL
GoLang.org, which was chosen since “go.org was not available to us.” As
a result, some individuals use the terms “GoLang” and “Go” interchange-
ably when referring to the programming language.
To be fair, GoLang is far more Google-able than Go, which may refer to
either the strategic game or the cult-classic Doug Liman film. GoLang is
also the Twitter hashtag for Go, #GoLang.
WHY IS Go SO POPULAR?
There may be as many viewpoints on this as there are Go programmers,
but two stand out:
Crash Course in GoLang ◾ 3
Python vs. Go
Python has been for more than 30 years, yet its popularity continues to
rise. The language’s design has withstood the test of time (despite some
rough spots along the way). Python and Go are two of the most popular
and user-friendly programming languages available today.
Python is an excellent object-oriented programming language, but
it is also possible to develop programs with a functional programming
approach. Python language is perhaps the most widely used program-
ming language among non-programmers. Python’s versatility is one of
the reasons it is so popular. Use for anything from cleaning out files on
your computer to developing online apps, serverless projects, teaching
programming to children, working on animation, etc.
Go PROGRAMMING FEATURES
• Language Design: The language designers deliberately decided to
keep the language basic and easy to grasp. The complete details are
contained inside a few pages, and several intriguing design decisions
were made using the language’s object-oriented capabilities. The lan-
guage is opinionated, promoting a conversational approach to prob-
lem-solving. Inheritance is favored over composition. “Do More with
Less” is the Go Language slogan.
Go includes contemporary development procedures for dealing
with open-source projects into handling external packages. A series
of simple commands allows us to fetch external packages and publish
our own packages straight from the tools.
the best of both worlds. Go, like C/C++, is a programming technique that
accounts for its speed. On the other hand, it employs garbage collection
and object removal for variable allocation, much like Java. As a result, Go
is an excellent programming language for working with any hardware
system.
Unmatched Simplicity of Go
One of the key advantages of using Go is its simplicity. Despite being a very
advanced language with a robust feature set, Go stands out from the crowd
owing to its ease of use and fundamental approach.
After learning the foundations, we’ll need to know the best programming
approaches for unique purposes and the standard library. A two- to three-
hour session, on the other hand, is enough to acquire the language.
BEGINNING WITH Go
Numerous online IDEs, like The Go Playground, repl.it, and many others,
can run Go applications without requiring any installation.
We need the following two pieces of software to install Go on our PCs
or laptops: Text editor and Compiler.
Text Editor
We can write our source code on a text editor’s platform. Below are some
text editors:
• Brief
• OS Edit command
• Epsilon
• Windows notepad
• VS Code
• Emacs
• vm or vi
Finding a Go Compiler
The Go distribution is provided as a binary installer for FreeBSD, Mac OS
X, Linux, and Windows with 32-bit (386) and 64-bit (amd64) x86 CPU
architectures.
INSTALL Go ON WINDOWS
We must first install GoLang on our machine before we can proceed.
We need a personal understanding of the Go Language and what it can
achieve. Go is an open-source, statically typed language developed by
Google’s Robert Griesemer, Rob Pike, and Ken Thompson in 2007 but only
published in 2009. It is also known as GoLang, and it supports the proce-
dural programming language. Initially, it intended to increase program-
ming efficiency on big codebases, multicore, and networked devices.
Crash Course in GoLang ◾ 9
GoLang programs are simple to create. They may be written in any plain
text editor, such as notepad++ or anything similar. To make creating and
working on GoLang code easier, one can utilize an online IDE or install
one on their machine. The best part is that the IDE makes writing GoLang
code easier because IDEs have numerous capabilities such as an intuitive
code editor, debugger, compiler, etc.
First, install the Go Language on the system to develop GoLang Codes
and conduct different exciting and beneficial tasks.
go version
If GoLang has been installed on our PC, it will create a message with all
the GoLang version’s data; otherwise, an error reading “Bad command or
file name” will occur.
• Step 1: After we’ve downloaded the archive file, unzip it. We’ll dis-
cover a go folder in our current working directory after unzipping.
• Step 2: Copy/paste the extracted folder to anywhere we want it to go.
In this situation, we’ll install it on the C drive.
• Step 3: Configure the environment variables now. Right-click My
Computer and choose Properties. Select Advanced System Settings
from left menu, followed by Environment Variables.
• Step 4: Choose Path and then Modify from the system variables.
Then, choose New and type in the Path with bin directory where we
placed the Go folder. We’ll update the path to C:gobiC:\go\bin and
click OK.
10 ◾ GoLang: The Ultimate Guide
For the Variable name, enter GOROOT, and for the Variable value, enter
the path to our GoLang folder. As a result, the Variable value in this exam-
ple is C:\go\. Click OK once we’ve completed filling out the form.
Then, under Environment Variables, click OK, and our configuration is
finished. Now, use the command prompt to check the GoLang version by
entering the Go version.
Following the download, any text editor or IDE may use to write
GoLang Codes, which can launch on the IDE or the Command prompt
with the following command:
go run filename.go
package main
import "fmt"
func main() {
// print
fmt.Println("Hello-everyone")
}
The fmt package has sent the Println method, which shows the output
in this scenario.
Comment: Comments, like those used in Java, C, and C++, are used
to clarify code. Compilers ignore and do not execute comment items.
Comments can be of one or more lines long.
• SingleLine comment
Syntax:
// singleline-comment
• Multiline comment
Syntax:
/* multi-line comment */
Example:
package main
import "fmt"
func main() {
fmt.Println("3 + 3 =", 3 + 3)
}
Hardware Restrictions
Over a decade, we’ve seen hardware and processor configurations change
rapidly. The P4 had a clock speed of 3.0 GHz in 2004. The Macbook Pro has
a clock speed of about in 2018. (2.3 GHz vs. 2.66 GHz). Additional proces-
sors are used to speed up functionality. However, the expense of utilizing
more processors grows as well. Consequently, we employ fewer processors,
and with fewer processors, we have a heavy programming language whose
threading uses more memory and slows down the speed of our system.
To resolve this challenge, GoLang was intended to utilize goroutine
instead of threading, which is comparable to threading but consumes con-
siderably less memory. Because threading requires 1 MB of memory and
goroutines consume 2 KB, it is simple to activate millions of goroutines
simultaneously. As a result of the above arguments, GoLang is a powerful
language that manages concurrency in the same manner as C++ and Java.
Downsides:
TERMINAL
GoLang has a terminal emulator, allowing us to communicate with our
command-line shell within the IDE. It can run Git commands, change
file permissions, and do other command-line tasks without using specific
terminal software.
The terminal emulator starts with our default system shell, but it also
supports Windows PowerShell, Command Prompt cmd.exe, sh, bash, zsh,
csh, and other shells.
However, we may right-click any file (for instance, in the Project tool
window and any open tab) and select Open in Terminal from the dialog
box to open the Terminal tool window with a new session in the directory
of the file.
INSTALL Go ON Mac
We should first install GoLang on our machine before we proceed. We need
a personal understanding of the Go Language and what it can achieve. Go
is an open-source, statically typed language developed by Google’s Robert
Griesemer, Rob Pike, and Ken Thompson in 2007, but only published in
2009. It is also known as GoLang, and it enables the procedural computer
program. It was created to increase programming efficiency on huge code-
bases, multicore, and networked devices.
GoLang applications are written with any plain text editor, including
TextEdit, Sublime Text, etc. To make creating and working on GoLang
code easier, one can utilize an online IDE or install one on their machine.
Using an IDE for simplicity makes writing GoLang code easier since IDEs
provide various capabilities such as an intuitive code editor, debugger,
compiler, etc.
Crash Course in GoLang ◾ 15
Implement a Go Program
Let’s save the source code to a file, compile it, and run the program. Please
follow the following steps:
Hello-Everyone
Check that the Go compiler is in our path but is executing in the direc-
tory containing the source file heyy.go.
Syntax:
func Create(filename string) (*File, error)
Example:
package main
import (
"log"
"os"
)
func main() {
// creation of an empty file
// Using the Create() method
myfile, es := os.Create("heyy.txt")
if es != nil {
log.Fatal(es)
}
log.Println(myfile)
myfile.Close()
}
Syntax:
func IsNotExist(es error) bool
Example:
package main
import (
"log"
"os"
)
var (
myfile *os.FileInfo
es error
)
func main() {
// The Stat() method returns file information,
and if there is no file, it gives error.
myfile, es := os.Stat("heyy.txt")
if es != nil {
// Using the IsNotExist() method to
determine whether a given file exists or not
if os.IsNotExist(es) {
log.Fatal("File was not found")
}
}
log.Println("File-Exist")
log.Println("File-Details:")
log.Println("The Name is: ", myfile.Name())
log.Println("The Size is: ", myfile.Size())
}
package main
import (
"log"
"os"
)
20 ◾ GoLang: The Ultimate Guide
func main() {
if er := os.Mkdir("a", os.ModePerm); er != nil {
log.Fatal(er)
}
}
package main
import (
"log"
"os"
)
func main() {
if er := os.MkdirAll("a/b/c/d", os.ModePerm); er
!= nil {
log.Fatal(er)
}
}
The os.Mkdir() method creates a new directory with the given name but
does not enable subdirectories to be created.
Example: Use the offline compiler for the optimal outcomes. Save the
file as an a.go extension. To run the application, execute the command
listed below.
go run file-name.go
func main() {
CreateFile()
ReadFile()
}
Syntax:
func Rename(oldpath, newpath string) error
Example:
// A program that demonstrates how to rename and
delete files in a new directory.
package main
import (
"log"
"os"
)
func main() {
// File Rename and Remove
// Using the Rename() method
OriginalPath := "/Users/anki/Documents/new_
folder/heyy.txt"
NewPath := "/Users/anki/Documents/new_folder/
myfolder/xyz.txt"
es := os.Rename(OriginalPath, NewPath)
if es != nil {
log.Fatal(es)
}
}
24 ◾ GoLang: The Ultimate Guide
if er != nil {
log.Fatalf("it failed to open")
}
//bufio. NewScanner()' function is called, and an
object os.File is passed as a parameter.
//This function returns an object bufio.Scanner which
is utilized on the
//bufio.Scanner.Split() method.
scanner := bufio.NewScanner(file)
// bufio.ScanLines is used as
// the input to method bufio.Scanner.Split()
// then scanning forwards to each new line
// using bufio.Scanner.Scan() method.
scanner.Split(bufio.ScanLines)
var text []string
for scanner.Scan() {
text = append(text, scanner.Text())
}
// method os.File.Close() is called
// on the os.File object to close
Crash Course in GoLang ◾ 25
file.Close()
// then a loop iterates through,
// the prints each of slice values.
for _, each_ln := range text {
fmt.Println(each_ln)
}
}
BASIC SYNTAX
Tokens
A Go program is made up of many tokens. Keywords, identifiers, con-
stants, string literals, and symbols are examples of tokens. To illustrate, the
preceding Go expression is composed of six tokens:
fmt.Println("Hey, Everyone")
fmt
.
Println
(
"Hey, Everyone"
)
Line Separator
The line separator key serves as a statement terminator in a Go program.
In all the other languages, individual expressions do not necessitate using
a specific separator, such as “;” in C. The Go compiler uses the statement
terminator “;” to indicate the conclusion of one logical entity.
Consider the following statements, for example:
fmt.Println("Hey, Everyone")
fmt.Println("We are now engaged in the environment of
Go programming")
Comments
Comments are comparable to help messages in our Go program, which
the compiler ignores. They commence with/* and end with the characters
*/as demonstrated below:
Identifiers
A Go identifier identifies a variable, function, or another user-defined item.
An identifier begins with a letter from A to Z, a to z, or an underscore.
Underscores can accompany it, zero or more characters, or numerals.
Keywords
The following are the reserved words in Go. These reserved words may not
be used as names for constants, variables, or other identifiers.
They are grouped into six categories: const, func, import, package,
type, and var are used in Go programs to declare distinct sorts of code
components.
Components of certain composite type denotations include chan, inter-
face, map, and struct.
Break, case, continue, default, else, fallthrough, for, goto, if, range,
return, select, and switch govern code flow.
Flow terms are controlled by both defer and go, but distinct ways.
Whitespace
Blanks, tabs, newline characters, and comments are examples of whitespace
in Go. A blank line contains only whitespace, maybe with a remark, and is
entirely disregarded by the Go compiler.
Whitespaces separate one segment of a statement from the next, allow-
ing the compiler to discern where one element, int, finishes and the next
element, int, begins in a statement. As a consequence, the given statement
is correct:
There must be at least one whitespace character for the compiler to differ-
entiate between int and ages (typically a space). Take the following state-
ment in contrast:
DATA TYPES IN Go
Data types specify the data types stored in a valid Go variable. The Go
Language divides types into various categories, which are as follows:
This section will go through the fundamental data types in the Go pro-
gramming language. The Basic Data Types are even further split into three
subcategories, as follows:
• Numbers
• Booleans
• Strings
Numbers
In Go, numbers are divided into three subcategories, which are as follows:
• Integers: The Go programming language supports both signed and
unsigned numbers in four sizes, as shown in the table. Signed inte-
gers are indicated by int, whereas unsigned integers are denoted by
uint.
Example:
// Integers are used in this program to
demonstrate their use
package main
import "fmt"
func main() {
Crash Course in GoLang ◾ 29
Example:
// illustrate the use of floating-point numbers
package main
import "fmt"
func main()
{
c := 22.46
d := 35.88
// Subtract of two floating-point number
e := d-c
// Display the result
fmt.Printf("The Result is: %f", e)
// Display the type of c variable
fmt.Printf("\nThe type of e is : %T", e)
}
Example:
// Illustrate use of the complex numbers
package main
import "fmt"
func main() {
var c complex128 = complex(17, 2)
var d complex64 = complex(9, 2)
fmt.Println(c)
fmt.Println(d)
// Display the type
fmt.Printf("The type of c is %T and "+
"the type of d is %T", c, d)
}
Booleans
The boolean data type only represents two values: true and false. Boolean
values are neither inherently nor explicitly changed to any other type.
Example:
// A program that demonstrates the use of Boolean
package main
import "fmt"
func main() {
// variables
strng1 := "PiiksofPiiks"
strng2:= "piiksofpiiks"
strng3:= "PiiksofPiiks"
result1:= strng1 == strng2
result2:= strng1 == strng3
// Display the result
fmt.Println( result1)
fmt.Println( result2)
// Display type of the
// result1 and result2
fmt.Printf("The type of result1 is %T and "+
"the type of result2 is %T",
result1, result2)
}
Strings
A string data type comprises a sequence of Unicode code points. In other
words, a string is a collection of immutable bytes, which means that we
Crash Course in GoLang ◾ 31
Example:
// A program that demonstrates the use of strings.
package main
import "fmt"
func main()
{
// strng variable stores strings
strng := "PiiksofPiiks"
// Display length of the string
fmt.Printf("The Length of the string is:%d",
len(strng))
// Display the string
fmt.Printf("\nthe String is: %s", strng)
// Display the type of strng variable
fmt.Printf("\nType of strng is: %T", strng)
}
VARIABLES IN Go
A typical program uses several variables that might change during execu-
tion. Consider a code that performs different operations on the data user
input. The values entered by one user may differ from those of another. As
an outcome, variables are necessary. This is so another user may not use
the same settings again.
When a person begins a new value in the operation process, which
will be used later, they can temporarily store it in the computer’s Random
Access Memory. The values in this part of memory change throughout the
execution, giving birth to another term for this, Variables. A variable is a
placeholder for information that may change during runtime. Variables
allow us to retrieve and manipulate stored data.
Variable naming guidelines:
• Begin the variable name with a letter or an underscore (_).
Furthermore, the letters ‘a-z’ or ‘A-Z’ and the numerals 0-9, and the
symbol ‘_’ may occur in the names.
Piiks piiks, _piiks24 // valid variable
124Piiks, 24piiks // invalid variable
32 ◾ GoLang: The Ultimate Guide
Declaring a Variable
In the Go computer language, we may declare variables in two ways:
Syntax:
var variablename type = expression
Important notes:
Example:
// Explain the variable concept
package main
import "fmt"
func main() {
// Variable-declared &
// initialized without the specified type
var my_variable1 = 40
var my_variable2 = "PiiksofPiiks"
var my_variable3 = 42.70
// Display the value and
Crash Course in GoLang ◾ 33
// type of variables
fmt.Printf("The Value of my_variable1 is : %d\n",
my_variable1)
fmt.Printf("The Type of my_variable1 is : %T\n",
my_variable1)
fmt.Printf("The Value of my_variable2 is : %s\n",
my_variable2)
fmt.Printf("Type of my_variable2 is : %T\n",
my_variable2)
fmt.Printf("The Value of my_variable3 is : %f\n",
my_variable3)
fmt.Printf("The Type of my_variable3 is : %T\n",
my_variable3)
}
Example:
// Variables are used in this program to
demonstrate the concept of variable.
package main
import "fmt"
func main() {
// Variable-declared &
// initialized without expression
var my_variable1 int
var my_variable2 string
var my_variable3 float64
// Display zero value of the variables
fmt.Printf("Value of my_variable1 is : %d\n",
my_variable1)
fmt.Printf("Value of my_variable2 is : %s\n",
my_variable2)
fmt.Printf("Value of my_variable3 is : %f",
my_variable3)
}
Example:
// Program to illustrate the concept of variable
package main
import "fmt"
func main() {
// Multiple variables of the same kind
// in a single line, variables are declared and
initialized
var my_variable1, my_variable2, my_variable3
int = 14, 354, 98
// Display the values of the variables
fmt.Printf("Value of my_variable1 is : %d\n",
my_variable1)
fmt.Printf("Value of my_variable2 is : %d\n",
my_variable2)
fmt.Printf("Value of my_variable3 is : %d",
my_variable3)
}
Example:
// Program to show the
// concept of variable
package main
import "fmt"
func main() {
// Multiple variables of the different types
// are declared and initialized in single line
var my_variable1, my_variable2, my_variable3 = 14,
"XYZ", 79.26
// Display the value &
// type of the variables
fmt.Printf("Value of my_variable1 is : %d\n",
my_variable1)
fmt.Printf("Type of my_variable1 is : %T\n",
my_variable1)
fmt.Printf("\nValue of the my_variable2 is : %s\n",
my_variable2)
Crash Course in GoLang ◾ 35
Example:
// Here, os.Open function return
// a file in the c variable and an error
// in the d variable
var c, d = os.Open(name)
Syntax:
variable-name:= expression
Important notes:
• The type of the expression determines the type of the variable in the
previous expression.
Example:
// Program to show the
// concept of variable
package main
import "fmt"
func main()
{
// Using the short-variable declaration
36 ◾ GoLang: The Ultimate Guide
my_var1 := 39
my_var2 := "PiiksofPiiks"
my_var3 := 32.63
// Display the value and type of the variables
fmt.Printf("Value of my_var1 is : %d\n", my_var1)
fmt.Printf("Type of my_var1 is : %T\n", my_var1)
fmt.Printf("\nValue of my_var2 is : %s\n",
my_var2)
fmt.Printf("Type of my_var2 is : %T\n", my_var2)
fmt.Printf("\nValue of my_var3 is : %f\n",
my_var3)
fmt.Printf("Type of my_var3 is : %T\n", my_var3)
}
Example:
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main()
{
// Using the short variable declaration
// Multiple variables of same types
// are declared & initialized in the single line
my_var1, my_var2, my_var3 := 630, 34, 76
// Display the value and
// type of the variables
fmt.Printf("The Value of my_var1 is : %d\n",
my_var1)
fmt.Printf("The Type of my_var1 is : %T\n",
my_var1)
Crash Course in GoLang ◾ 37
Example:
// os.Open function return a
// file in the c variable and an
// error in the d variable
c, d := os.Open(name)
// Program to show
// concept of the variable
package main
import "fmt"
func main() {
// Using short variable declaration
// short variable declaration acts as
// an assignment for the my_var2 variable
// because the same variable present in same
block
// so the value of my_var2 is changed from 56 to
100
my_var1, my_var2 := 39, 56
my_var3, my_var2 := 56, 100
// If we try to run the commented lines,
38 ◾ GoLang: The Ultimate Guide
Example:
// Program to show the
// concept of the variable
package main
import "fmt"
func main() {
// Using short-variable declaration
// Multiple variables of the different types
// are declared and initialized in the single line
my_var1, my_var2, my_var3 := 800, "Piiks", 58.26
// Display the value and type of variables
fmt.Printf("Value of my_var1 is : %d\n", my_var1)
fmt.Printf("Type of my_var1 is : %T\n", my_var1)
fmt.Printf("\nValue of my_var2 is : %s\n", my_var2)
fmt.Printf("Type of my_var2 is : %T\n", my_var2)
fmt.Printf("\nValue of my_var3 is : %f\n", my_var3)
fmt.Printf("Type of my_var3 is : %T\n", my_var3)
}
CONSTANTS
It is fixed, as the name CONSTANTS indicates; likewise, once the value of
a constant is specified in a programming language, it cannot change fur-
ther. Constants can be of any basic data type, including integer constants,
floating constants, character constants, and literal strings.
Crash Course in GoLang ◾ 39
Example:
package main
import "fmt"
const Pie = 3.14
func main()
{
const POP = "PiiksofPiiks"
fmt.Println("Hello", everyone)
fmt.Println("Happy", Pie, "Day")
const Correct= true
fmt.Println("Go rules?", Correct)
}
Numeric Constant
Numeric constants are quantities that have a high degree of accuracy.
Operations that mix numeric types are not permitted in Go since it is a
40 ◾ GoLang: The Ultimate Guide
Integer Constant
• 45 : decimal
• 0312 : octal
• 0x3b : hexadecimal
• 20 : int
• 20u : unsigned int
• 20l : long
• 20ul : unsigned long
• 232 : Legal
• 225u : Legal
• 0xFeeL : Legal
• 068 : Illegal: 8 is not an octal digit
• 042UU : Illegal: cannot repeat a suffix
• 3.14149 : Legal
• 314149E-5L : Legal
• 520E : Illegal : incomplete exponent
• 220f : Illegal : no decimal or exponent
• .e56 : Illegal: missing integer or fraction
String Literals
Go offers two types of string literals: “ ” (double-quote style) and
‘ ’(back-quote).
Strings can be concatenated using the + and += operators.
They are plain characters, escape sequences, and universal characters,
characters in a string are similar to character literals.
This is an example of untyped.
String types with zero values are blank strings, which can be repre-
sented in literal by “or”.
Strings of all kinds can be compared using operators like ==,!=, and (for
comparing of same types).
42 ◾ GoLang: The Ultimate Guide
Syntax:
type _string struct
{
elements *byte // underlying-bytes
len int //number of bytes
}
First example:
"hello, piiksofpiiks"
"hello, \
piiksofpiiks"
"hello " "piiks" "ofpiiks"
Second example:
package main
import "fmt"
func main()
{
const C = "POP"
var D = "PiiksofPiiks"
// Concat the strings.
var helloEveryone = C+ " " + D
helloEveryone += "!"
fmt.Println(helloEveryone)
// Compare the strings.
fmt.Println(C == "POP")
fmt.Println(D < C)
}
Boolean Constant
Constants of both types are string constants and Boolean constants. It
complies with the same rules as a string constant. The primary distinction
is that it includes two untyped constants: true and false.
Example:
package main
import "fmt"
const Pie = 3.14
Crash Course in GoLang ◾ 43
func main()
{
const trueConst = true
// Type definition using type keyword
type my_Bool bool
var default_Bool = trueConst // allowed
var custom_Bool my_Bool = trueConst // allowed
// default_Bool = custom_Bool // not-allowed
fmt.Println(default_Bool)
fmt.Println(custom_Bool)
}
VARIABLE SCOPE IN Go
The scope of a variable may be defined as the area of the program where a
given variable is available. Declare a variable in a class, method, loop, or
other structure. All identifiers in GoLang, like those in C/C++, are lexi-
cally (or statically) scoped, which implies that the variable’s scope is deter-
mined at compilation time. On the other hand, a variable may only be
called from inside the code block in which it is defined.
Variable scope rules in GoLang are divided into two categories depend-
ing on where the variables are declared:
• Local Variables
• Global Variables
Local Variables
• Variables defined within a function or a block are local variables.
These are unreachable outside of the function or block.
• These variables can also declare within for, while, and similar expres-
sions in a function.
• On the other hand, retrieve these variables through nested code
blocks within a function.
• These variables are also known as block variables.
• A compile-time error will occur if these variables are declared twice
with the same name in the same scope.
• These variables are no longer present when the function’s execution
is complete.
44 ◾ GoLang: The Ultimate Guide
• The variable defined outside the loop is accessible from within the
nested loops. It denotes that a global variable is accessible to all func-
tions and loops. The function’s loop and function will access the local
variable.
• A variable declared within a loop body is invisible to the outside
world.
Example:
// Example of a program to demonstrate local
variables
package main
import "fmt"
// the main function
func main() { // the local level scope of the main
function begins here.
// inside the main function, local variables
var my_variable1, my_variable2 int = 90, 47
// Variable values are displayed
fmt.Printf("Value of my_variable1 is : %d\n",
my_variable1)
fmt.Printf("Value of my_variable2 is : %d\n",
my_variable2)
} // the main function's local level scope
terminates here.
Global Variables
Example:
// To demonstrate the global variables, write a
program
package main
Crash Course in GoLang ◾ 45
import "fmt"
// global-variable declaration
var my_variable1 int = 120
func main() { // from here the local level scope
begins
// the local variables inside main function
var my_variable2 int = 220
// Display the value of global variable
fmt.Printf("The Value of Global my_variable1 is :
%d\n",
my_variable1)
// Display value of the local variable
fmt.Printf("The Value of Local my_variable2 is :
%d\n",
my_variable2)
// calling the function
display()
} // local level scope ends
// taking function
func display() { // the local level begins
// Display the value of global variable
fmt.Printf("The Value of Global my_variable1 is :
%d\n",
my_variable1)
} // the local scope terminates here
Note: What happens if a function has a local variable with the same name
as a global variable?
The solution is simple: The compiler will prefer the local variable. The
compiler issues a compile-time error typically when two variables with
similar names are defined. The compiler will, however, accept variables
provided in different scopes. When a local variable with the same name as
a global variable is defined, the compiler will prioritize the local variable.
The output is shown in the example below. As my_variable1 in function,
main has a value of 220. As a result, a local variable has a high preference
over a global variable.
Example:
package main
import "fmt"
func main() {
var width, height int = 220, 60 //declaring
multiple-variables
fmt.Println("width :", width, "height :",
height)
}
Suppose the variables have an initial value, then remove the type. The int
type may delete because the variables in the previous program have start-
ing values.
Example:
package main
import "fmt"
func main() {
var width, height = 220, 60 //"int" is dropped
fmt.Println("width :", width, "height :",
height)
}
Crash Course in GoLang ◾ 47
For example, the above program will produce a width of 220 and a height
of 60.
We should have figured that if no initial value for width and height is
specified, we will set them to 0.
Example:
package main
import "fmt"
func main() {
var width, height int
fmt.Println("width :", width, "height :",
height)
width = 220
height = 60
fmt.Println("new width :", width, "new height :",
height)
}
var (
nme1 = initialvalue1
nme2 = initialvalue2
)
Using the syntax explained above, the following program defines variables
of various types.
package main
import "fmt"
func main() {
var (
name = "harshita"
age = 23
height int
)
fmt.Println("my name :", name, ", age :", age,
"and height :", height)
}
48 ◾ GoLang: The Ultimate Guide
SHORTHAND DECLARATION
Go also includes a more condensed method of defining variables. This is
known as a shorthand statement, and it uses the := operator.
Name := initialvalue is the shorthand for defining a variable.
Using the shorthand syntax, the following program declares a variable
count with a value of 12. Because count began with the integer value 12,
Go infers that it is of the type int.
package main
import "fmt"
func main() {
count := 14
fmt.Println("Count =",count)
}
package main
import "fmt"
func main() {
name, age := "harshita", 23 //short-hand
declaration
fmt.Println("my name :", name, "age :", age)
}
The given code declares two variables of the types string and int.
If we run the software mentioned above, we will see my name, harshita,
and my age, 23, printed.
The assignment of initial values to all variables on the left side of the
assignment is required by shorthand declaration. The following program
will generate an assignment mismatch error since it has two variables but
only one value. This is since age has not been assigned a monetary value.
package main
import "fmt"
func main() {
name, age := "harshita" //error
fmt.Println("my name :", name, "age :", age)
}
Crash Course in GoLang ◾ 49
Shorthand syntax may be used only when at least one of the variables
on the left side of := is newly declared. Consider the following program:
package main
import "fmt"
func main() {
c, d := 40, 20 // declare variables c and d
fmt.Println("c is", c, "d is", d)
c, d := 60, 30 // d is already declared but e is new
fmt.Println("d is", d, "e is", e)
d, e = 20, 70 // assign new values to already
declared variables d and e
fmt.Println("changed d is", d, "e is", e)
}
package main
import "fmt"
func main() {
c, d := 30, 40 //x and y declared
fmt.Println("c is", c, "d is", d)
c, d := 30, 40 //error, no new variables
}
OPERATORS IN Go
Operators are the fundamental building elements of all programming
languages. Consequently, the Go Language’s functionality is inadequate
without the use of operators. Operators enable us to perform a variety of
operations on operands. In the Go programming language, operators are
categorized depending on their capabilities:
• Arithmetic Operators
• Misc Operators
• Relational Operators
• Bitwise Operators
50 ◾ GoLang: The Ultimate Guide
• Logical Operators
• Assignment Operators
Operators in Go.
Arithmetic Operators
These are used in Go to perform arithmetic/mathematical operations on
operands:
Example:
// A program to demonstrate the usage of
arithmetic operators.
Crash Course in GoLang ◾ 51
package main
import "fmt"
func main()
{
c:= 47
d:= 72
// Addition
result1:= c + d
fmt.Printf("The Result of c + d = %d", result1)
// Subtraction
result2:= c - d
fmt.Printf("\n The Result of c - d = %d", result2)
// Multiplication
result3:= c * d
fmt.Printf("\n The Result of c * d = %d", result3)
// Division
result4:= c / d
fmt.Printf("\n The Result of c / d = %d", result4)
// Modulus
result5:= c % d
fmt.Printf("\n The Result of c %% d = %d", result5)
}
Relational Operators
Relational operators in Go are used to compare two values. Let’s take a
sneak peek at some of them:
• The operator ‘==’ (Equal To) detects whether or not the two operands
are equal. If this is the case, the function then returns true. If it does
not, it returns false. For example, 9==9 will yield true.
• The ‘!=’ operator determines if the two operands supplied are equal.
It returns true if it does not. If it does not, it returns false. It is the
boolean counterpart of the equals sign. For example, 9!=9 will yield
false.
• If the first operand is greater than the second in the code, the
‘>’(Greater Than)operator is used. If this is the case, the function
then returns true. If it does not, it returns false. 9>6, for example,
will return true.
52 ◾ GoLang: The Ultimate Guide
• The (Less Than)operator detects if the first operand is less than the
second operand. If this is the case, the function then returns true.
If it does not, it returns false. 64, for example, will get a misleading
result.
• The ‘>=’ (Greater Than or Equal To)operator returns true if the first
operand is greater than or equal to the second operand. If it does not,
it returns false. For example, 9>=9 will yield true.
• If the first operand is less than or equal to the second operand, the
‘<=’ (Least Than or Equal To)operator returns true. If it does not, it
returns false. For example, 9<=9 will likewise yield true.
Example:
// Program to show the use of the relational
operators
package main
import "fmt"
func main() {
c:= 38
d:= 25
// '=='(Equal To)
result1:= c == d
fmt.Println(result1)
// '!='(Not Equal To)
result2:= c != d
fmt.Println(result2)
// '<'(Less Than)
result3:= c < d
fmt.Println(result3)
// '>'(Greater Than)
result4:= c > d
fmt.Println(result4)
// '>='(Greater Than Equal To)
result5:= c >= d
fmt.Println(result5)
// '<='(Less Than Equal To)
result6:= c <= d
fmt.Println(result6)
}
Crash Course in GoLang ◾ 53
Logical Operators
Logical operators in Go are used to combine two or more conditions or
enhance the original state’s evaluation.
• Logical AND: When both requirements are met, the && opera-
tor returns true. If it does not, it returns false. For example, c && d
returns true when both c and d are true (i.e., non-zero).
• Logical OR: The ‘||’ operator returns true when one or both of the
prerequisites are satisfied. If it does not, it returns false. c || d, for
example, returns true if either c or d is true (i.e., non-zero). It returns
true if both c and d are true.
• If the condition is not fulfilled, the ‘!’ operator returns true. If it does not,
it returns false. !c For example, returns true if it is false, i.e., when c=0.
Example:
// Program to show the use of logical operators
package main
import "fmt"
func main() {
var c int = 46
var d int = 85
if(x!=y && x<=y){
fmt.Println("True")
}
if(c!=d || c<=d){
fmt.Println("True")
}
if(!(c==d)){
fmt.Println("True")
}
}
Bitwise Operators
Six bitwise operators function at the bit level or perform bit-by-bit opera-
tions in the Go programming. The bitwise operators are as follows:
• & (bitwise AND): Takes two operands and applies the AND operator
to each bit of the two integers. AND only returns 1 if both bits are 1.
• | (bitwise OR): Takes two operands and applies the OR operator on each bit
of the two numbers. If either of the two bits is 1 OR produces a result of 1.
54 ◾ GoLang: The Ultimate Guide
• ^ (bitwise XOR): Takes two operands and applies the XOR function
on each bit of the two integers. If two bits are not the same, the out-
come of XOR is 1.
• << (left shift): The first operand’s bits are left-shifted, while the sec-
ond operand specifies the number of places to shift.
• >> (right shift): Takes two integers, shifts the first operand’s bit to the
right, and the second operand determines the number of places to shift.
• &^ (AND NOT): This is an easy-to-understand operator.
Example:
// A program that demonstrates the usage of
bitwise operators.
package main
import "fmt"
func main() {
c:= 46
d:= 85
// & (bitwise AND)
result1:= c & d
fmt.Printf("Result of c & d = %d", result1)
// | (bitwise OR)
result2:= c | d
fmt.Printf("\nResult of c | d = %d", result2)
// ^ (bitwise XOR)
result3:= c ^ d
fmt.Printf("\nResult of c ^ d = %d", result3)
// << (left shift)
result4:= c << 1
fmt.Printf("\nResult of c << 1 = %d", result4)
// >> (right shift)
result5:= c >> 1
fmt.Printf("\nResult of c >> 1 = %d", result5)
// &^ (AND NOT)
result6:= c &^ d
fmt.Printf("\nResult of c &^ d = %d", result6)
}
Assignment Operators
Assignment operators are used to assigning a value to a variable. The
left operand of the assignment operator is a variable, whereas the right
Crash Course in GoLang ◾ 55
operand is a value. The right value must be of the same data type as the
variable on the left, or the compiler will raise an error. Assignment opera-
tors include the following:
Example:
// Program to demonstrate the usage of assignment
operators
package main
import "fmt"
func main()
{
var c int = 46
var d int = 85
// "="(Simple Assignment)
c= d
fmt.Println(c)
// "+="(Add Assignment)
c += d
fmt.Println(c)
//"-="(Subtract Assignment)
c-=d
fmt.Println(c)
// "*="(Multiply Assignment)
c*= d
fmt.Println(c)
// "/="(Division Assignment)
c /= d
fmt.Println(c)
// "%="(Modulus Assignment)
c %= d
fmt.Println(c)
}
Misc Operators
Example:
// Program to show the use of Misc Operators
package main
import "fmt"
Crash Course in GoLang ◾ 57
func main() {
c := 6
// Using address of operator(&) and
// pointer indirection(*) operator
d := &c
fmt.Println(*d)
*d = 7
fmt.Println(c)
}
CONTROL STATEMENTS
The developer must declare one or more conditions that the code will eval-
uate or test, statements executed if the condition is true, and optionally,
further statements that will execute if the condition is false.
The Go programming language supports the following decision-making
statements.
if Statement
This is the most direct decision-making statement. It is used to determine
whether or not a specific statement or block of statements will be executed;
for example, if a specified condition is true, then a block of statements is
run; otherwise, it is not.
Syntax:
if(condition)
{
// Statement to execute if condition is true
}
58 ◾ GoLang: The Ultimate Guide
Statement of if.
Example:
// A program to demonstrate the use of the if
statement
package main
import "fmt"
func main() {
// taking the local variable
var d int = 600
// using if statement for checking the condition
if(d < 1000) {
// print following if
// condition evaluates to true
fmt.Printf("d is less than 1000\n")
}
fmt.Printf("Value of d is : %d\n", d)
}
if…else Statement
If the condition is true, the if statement will execute a block of statements;
if the condition is false, the block of statements will not run. But what
if the condition is false and we want to do something different? This is
Crash Course in GoLang ◾ 59
when the else statement comes into effect. When the condition is false, we
may run a code block using the else statement in conjunction with the if
statement.
Syntax:
if (condition)
{
// executes this block if the
// condition true
} else {
// executes this block if the
// condition false
}
Statement of if-else.
Example:
// Program to show the use of if...else statement
package main
import "fmt"
func main() {
// taking local variable
var d int = 3200
// using the if statement for
// checking condition
60 ◾ GoLang: The Ultimate Guide
Nested if Statement
A nested if statement in Go is an if statement that is the target of another
if or else expression. A nested if statement is a statement nestled inside
another if statement. In GoLang, we may nest if statements within if state-
ments. In other words, we may nest one if the expression is inside another.
Syntax:
if (condition1) {
// executes when the condition1 true
if (condition2) {
// executes when the condition2 true
}
}
Statement of nested-if.
Crash Course in GoLang ◾ 61
Example:
// Program to show the use of nested if statement
package main
import "fmt"
func main() {
// taking two local-variable
var d1 int = 700
var d2 int = 300
// using if statement
if( d1 == 700 ) {
// if condition is true then
// check the following
if( d2 == 800 ) {
// if the condition is true
// then display following
fmt.Printf("Value of d1 is 700 and d2 is
300\n" );
}
}
}
if..else..if Ladder
A user can choose from many options here. The if statements are executed
in the order specified. The statement linked with that if is performed when
one of the criteria is fulfilled, and the rest of the ladder is skipped. If none
of the conditions are satisfied, the final else statement is executed.
Important notes:
• The if statement can be either zero or one, and it must come after any
other if statements.
• The else if statement in an if statement can include zero to many
other if statements and must come before the otherwise clause.
• If an else if statement succeeds, there is no need to test other if or else
statements.
Syntax:
if(condition_1) {
// this block will execute when condition_1 true
} else if(condition_2) {
62 ◾ GoLang: The Ultimate Guide
Statement of if-else-if.
Example:
// Program to demonstrate
// the use of if..else..if ladder
package main
import "fmt"
func main() {
// taking local-variable
var d1 int = 700
Crash Course in GoLang ◾ 63
// checking condition
if(d1 == 220) {
// if condition is true then
// display following */
fmt.Printf("Value of d1 is 220\n")
} else if(d1 == 350) {
fmt.Printf("Value of d1 is 350\n")
} else if(d1 == 410) {
fmt.Printf("Value of d1 is 410\n")
} else {
// if none of the conditions is true
fmt.Printf("The None of values is
matching\n")
}
}
SWITCH STATEMENT
A switch statement illustrates a multiway branch statement. It provides an
efficient mechanism for moving execution to other code sections based on
the value of the expression. There are two kinds of switch statements in the
Go programming language:
• Expression Switch
• Type Switch
Expression Switch
The switch expression is similar to the switch statement in C, C++, and
Java. It enables us to conveniently redirect execution to different portions
of code dependent on the expression’s value.
Syntax:
switch optstatement; optexpression{
case exp1: Statement
case exp2: Statement
…
default: Statement
}
64 ◾ GoLang: The Ultimate Guide
Example:
// Program to demonstrate the notion of the
Expression switch statement
package main
import "fmt"
func main() {
// switch statement with the both
// optional statement, i.e, day:=3
// and the expression, i.e, day
switch day:=3; day{
case 1:
fmt.Println("Sunday")
case 2:
fmt.Println("Monday")
case 3:
fmt.Println("Tuesday")
case 4:
fmt.Println("Wednesday")
case 5:
fmt.Println("Thursday")
case 6:
fmt.Println("Friday")
case 7:
fmt.Println("Saturday")
default:
fmt.Println("Invalid")
}
}
Type Switch
A type switch is used when comparing types. The type that will compare
to the type in the switch expression is included in the case in this switch.
Syntax:
switch optstatement; typeswitchexpression{
case typelist 1: Statement
case typelist 2: Statement
…
default: Statement
}
Crash Course in GoLang ◾ 65
Example:
// A program that demonstrates the concept of a
type switch statement.
package main
import "fmt"
func main() {
var value interface{}
switch d:= value.(type) {
case bool:
fmt.Println("Value is of boolean type")
case float64:
fmt.Println("Value is of float64 type")
case int:
fmt.Println("Value is of int type")
default:
fmt.Printf("Value is of type: %T", d)
}
}
ARRAYS
Arrays in the GoLang scripting language are comparable to those in other
languages. We may need to retain a collection of data of the same type in
the program, such as a list of students’ grades. In a program, this type of
collection is held by an Array. An array is a fixed-length sequence used in
memory to store similar elements. Because of their restricted length, an
array is not as popular in the Go Language as Slice.
An array can store zero or more than zero items. The array items are
indexed with the [] index operator and their zero-based positioning; thus,
the index of the first element is array[0], and the index of the last element
is array[len(array)−1].
Syntax:
var array_name[length]Typle{item1, item2, item3,
...itemN}
66 ◾ GoLang: The Ultimate Guide
or
Var array_name[length]Type
Example:
// Program to demonstrate how to
// build an array with the var keyword
// and access array elements with their index
value.
package main
import "fmt"
func main() {
// Creation of array of string type
// Using var keyword
var myarr[3]string
// The elements are assigned using index
myarr[0] = "HEW"
myarr[1] = "Heyevryoneoworld"
myarr[2] = "Hey"
// accessing the elements of array
// Using index value
fmt.Println("The Elements of Array:")
fmt.Println("The Element 1 is: ", myarr[0])
fmt.Println("The Element 2 is: ", myarr[1])
fmt.Println("The Element 3 is: ", myarr[2])
}
Syntax:
array_name:= [length]Type{item1, item2, item3,...
itemN}
Example:
// A program to demonstrate how to build an array
using a shorthand declaration
// and how to retrieve the array's elements using
a for loop.
Crash Course in GoLang ◾ 67
package main
import "fmt"
func main() {
// the shorthand declaration of array
arr:= [4]string{"hey", "hew", "Hey1431",
"Heyeveryoneworld"}
// Accessing the elements of
// array Using for loop
fmt.Println("Elements of the array:")
for d:= 0; d < 3; d++{
fmt.Println(arr[d])
}
}
Multidimensional Array
Although we are already aware that arrays are one-dimensional, we can
make a multidimensional array. Multidimensional arrays are arrays of the
same kind. In Go, we may create a multidimensional array by using the
following syntax:
array_name[Length1][Length2]..[LengthN]Type
As seen in the code below, we may use the Var keyword or a shorthand
declaration to create a multidimensional array.
Example:
// program to demonstrate the concept of
multidimension arrays.
package main
import "fmt"
func main() {
// Creation and initializing
// two-dimensional-array
// Using shorthand-declaration
// (,) Comma is necessary
arry:= [3][3]string{{"C#", "C", "Scala"},
{"HTML", "C++", "PHP"},
{"Ruby", "C#", "Go"},}
// Accessing the values of
// array Using the for loop
fmt.Println("The Elements of Array 1")
68 ◾ GoLang: The Ultimate Guide
Syntax:
// creation of a copy of an array by value
arry := arr1
Crash Course in GoLang ◾ 69
Example:
// program that demonstrates how to copy an array
by value.
package main
import "fmt"
func main() {
// Creating, initializing array
// Using shorthand-declaration
my_arry1 := [5]string{"C++", "Go", "Ruby", "
Scala ", "C"}
// Copying array into the new variable
// elements are passed by value
my_arry2 := my_arry1
fmt.Println("Array_1: ", my_arry1)
fmt.Println("Array_2:", my_arry2)
my_arry1[0] = "C"
// when we copy an array into
// the another array by value then changes
made in the original
// array don't reflect in the copy of that array
fmt.Println("\nThe Array_1 is: ", my_arry1)
fmt.Println("The Array_2 is: ", my_arry2)
}
// For sized-array
func function_name(variable_name [size]type){
// Code..
}
70 ◾ GoLang: The Ultimate Guide
We may provide one or more dimensional arrays to the function using this
approach. Let us use an example here to demonstrate this point:
SLICES
Slice is a more efficient, adaptable, and accessible Go data structure than
an array. Multiple components cannot be placed in the same slice because
it is a variable-length sequence of items of the same type. It is similar to an
array in that it has a length and an index value. Unlike an array, though,
the size of the slice is extended. A slice and an array are connected inter-
nally; a slice refers to an underlying array. The slice may include duplicate
components. The first index point in a slice is always 0, and the last is
(length of slice − 1).
Slice Declaration
A slice is described in the same way as an array, except it does not specify
the size of the slice. As a result, it may grow and compress as needed.
Crash Course in GoLang ◾ 71
Syntax:
[]D
or
[]D{}
or
var myslice[]int
Slice Components
A slice is composed of three parts:
Example:
//program that demonstrates how the slice
components function.
package main
import "fmt"
func main() {
// Array-Creation
arry := [7]string{"This", "is", "instance",
"of", "Go", "language"}
// Display-array
fmt.Println("Array:", arry)
// Creation of a slice
72 ◾ GoLang: The Ultimate Guide
myslice := arry[1:6]
// Display-slice
fmt.Println("Slice:", myslice)
// Display length of the slice
fmt.Printf("The Length of the slice is: %d",
len(myslice))
// Display capacity of the slice
fmt.Printf("\nThe Capacity of the slice is: %d",
cap(myslice))
}
Example:
// program to demonstrate how to use a slice
literal to create a slice.
package main
import "fmt"
func main() {
// Creation of slice using var keyword
var myslice1 = []string{"Hey", "from",
"Everyone"}
fmt.Println("My Slice 1 is:", myslice1)
// Creation of a slice
//using shorthand-declaration
myslice2 := []int{34, 25, 67, 59, 31, 14, 75}
fmt.Println("My Slice 2 is:", myslice2)
}
Using an Array
We can construct a slice from the provided array since the slice is the
array’s reference. To make a slice from a given array, define the lower and
Crash Course in GoLang ◾ 73
upper boundaries, implying that the slice can receive elements from the
array starting with the lower bound and ending with the upper bound. It
excludes the things in the upper bound mentioned above. As shown in the
following cases:
Syntax:
arrayname[low:high]
Example:
// program to demonstrate how to create array
slices
package main
import "fmt"
func main() {
// Array-Creation
arry := [4]string{"Hey", "from", "Creator",
"HFC"}
// Creating slices from the given array
var myslice1 = aryr[1:2]
myslice2 := arry[0:]
myslice3 := arry[:2]
myslice4 := arry[:]
// Display-result
fmt.Println("My Array is: ", arry)
fmt.Println("My Slice 1 is : ", myslice1)
fmt.Println("My Slice 2 is: ", myslice2)
fmt.Println("My Slice 3 is: ", myslice3)
fmt.Println("My Slice 4 is: ", myslice4)
}
Syntax:
slicename[low:high]
74 ◾ GoLang: The Ultimate Guide
Example:
// Program to show how to create slices from slice
package main
import "fmt"
func main() {
// Creating-slice
oRignAl_slice := []int{60, 10, 40, 80,
52, 39, 61}
// Creating slices from the given slice
var myslice1 = oRignAl_slice[1:5]
myslice2 := oRignAl_slice[0:]
myslice3 := oRignAl_slice[:6]
myslice4 := oRignAl_slice[:]
myslice5 := myslice3[2:4]
// Display-result
fmt.Println("Original Slice is:",
oRignAl_slice)
fmt.Println("New Slice 1 is:", myslice1)
fmt.Println("New Slice 2 is:", myslice2)
fmt.Println("New Slice 3 is:", myslice3)
fmt.Println("New Slice 4 is:", myslice4)
fmt.Println("New Slice 5 is:", myslice5)
}
Syntax:
func make([]T, len, cap) []T
Example:
// Program to show how to create slices
// Using make-function
package main
Crash Course in GoLang ◾ 75
import "fmt"
func main() {
// Creating array of the size 8 and slice
this array till 3
// and return the reference of slice
// Using make function
var myslice1 = make([]int, 3, 8)
fmt.Printf("Slice 1 = %v, \nlength = %d,
\ncapacity = %d\n",
myslice1, len(myslice1),
cap(myslice1))
// Creating another array of the size 8
// and return the reference of slice
// Using make-function
var myslice2 = make([]int, 9)
fmt.Printf("Slice 2 = %v, \nlength = %d,
\ncapacity = %d\n",
myslice2, len(myslice2),
cap(myslice2))
}
Example:
// program to show
// iterating over a slice using the for loop
package main
import "fmt"
func main() {
// Creating-slice
myslice := []string{"This", "is", "the",
"instance",
"of", "Go", "programing"}
// Iterate using for-loop
for d := 0; d < len(myslice); d++ {
fmt.Println(myslice[d])
}
}
76 ◾ GoLang: The Ultimate Guide
Example:
// Program to demonstrate slice composite literal
package main
import "fmt"
func main() {
// Slice with composite literal
// Slice allows to group together
// values of the same type
// here the type of values is int
st1 := []int{33, 46, 29, 74}
// displaying-values
fmt.Println(st1)
}
Ints
This method only sorts an int slice, and the components in the slice are
sorted in ascending order.
Syntax:
func Ints(slc []int)
In this scenario, slc represents an int slice. Let us use an example here to
demonstrate this point:
IntsAreSorted
This function determines if the provided slice of ints is sorted or not (in
increasing order). This method then returns true if the slice is sorted; else,
it returns false.
Crash Course in GoLang ◾ 79
Syntax:
func IntsAreSorted(scl []int) bool
In this scenario, scl represents an int slice. Let us use an example here to
demonstrate this point:
This function creates a subslice of the original slice by deleting all pre-
ceding and trailing UTF-8-encoded code points from the input text. This
function returns the original slice with no modifications if the bytes slice
does not contain the necessary string. We must import the bytes package
in our program to utilize the Trim function because it is provided in the
bytes package.
Syntax:
func Trim(ori_slice[]byte, cut_string string) []byte
ori_slice is the original slice of bytes, and cut_string indicates a string that
we want to trim in the provided slice. Let’s dig deep using the example
given:
Syntax:
func Split(o_slice, sep []byte) [][]byte
Example:
// Program to demonstrate the concept of splitting
a slice of bytes
package main
import (
"bytes"
"fmt"
)
func main() {
// Creating and initializing slice of bytes
// Using shorthand-declaration
slice_1 := []byte{'!', '!', 'H', 'e', 'y',
'y', 'f',
'r', 'o', 'm', 'W', 'o', 'r', 'l', 'd',
'#', '#'}
slice_2 := []byte{'L', 'i', 'c', 'h', 'i'}
82 ◾ GoLang: The Ultimate Guide
STRING
Strings in Go are distinct from those in other languages, such as Java, C++,
Python, etc. It’s a string of variable-width characters, each represented by
one or more UTF-8-encoded bytes. Strings are either an immutable chain
of arbitrary bytes or a read-only slice of bytes whose bytes may be repre-
sented in Unicode text using UTF-8 encoding.
Because of UTF-8 encoding, a GoLang string may include material
mash-up of every language globally without generating confusion or
restricting the page. Strings are typically enclosed in double-quotes “”, as
shown in the given an example:
String Literals
In the Go programming language, string literals are created in two ways:
Using Backticks(")
Backticks(") are used to form string literals, also known as raw literals.
Raw literals do not support escape characters, span several lines, or include
characters other than the backtick. It is frequently used to generate multi-
line messages, regular expressions, and HTML.
Example:
// Program to show string literals
package main
84 ◾ GoLang: The Ultimate Guide
import "fmt"
func main() {
// Creating, and initializing a
// variable with the string literal
// Using double-quote
My_value_1 := "Welcome to Home"
// Adding escape character
My_value_2 := "Welcome!\nHome "
// Using backticks
My_value_3 := 'Hello!Everybody'
// Adding escape-character
// in the raw literals
My_value_4 := 'Hello!\nPiiksforPiiks'
// Displaying-strings
fmt.Println("The String 1 is: ", My_value_1)
fmt.Println("The String 2 is: ", My_value_2)
fmt.Println("The String 3 is: ", My_value_3)
fmt.Println("The String 4 is: ", My_value_4)
}
Trim
This method trims the text by deleting all of the stored procedure leading
and trailing Unicode code points.
Syntax:
func Trim(str string, cutstr string) string
Example:
// program that demonstrates how to trim string
package main
import (
Crash Course in GoLang ◾ 85
"fmt"
"strings"
)
// main-method
func main() {
// Creating and initializing the string
// Using shorthand-declaration
stry1 := "!!Welcome to Home!!"
stry2 := "@@This is a example of GoLang$$"
// Displaying -trings
fmt.Println("Strings-before-trimming:")
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is:", stry2)
// Trimming-given-strings
// Using the Trim() function
rest1 := strings.Trim(stry1, "!")
rest2 := strings.Trim(stry2, "@$")
// Displaying-results
fmt.Println("\nStrings-after-trimming:")
fmt.Println("Result 1 is: ", rest1)
fmt.Println("Result 2 is:", rest2)
}
TrimLeft
TrimLeft is a function that trims the string’s Unicode code points on the
left side.
Syntax:
func TrimLeft(str string, cutstr string) string
Example:
// program to demonstrate how to trim the left-
hand side components of a string
package main
import (
"fmt"
"strings"
)
// main-method
func main() {
86 ◾ GoLang: The Ultimate Guide
TrimRight
This method cuts the string’s right-hand side Unicode code points (speci-
fied in the function).
Syntax:
func TrimRight(str string, cutstr string) string
Example:
// Program to show how to
// trim the right-hand side elements from the
string
package main
import (
"fmt"
"strings"
)
// main-method
func main() {
// Creating, and initializing the string
// using shorthand declaration
stry1 := "!!Welcome to Home **"
stry2 := "@@This is an example of GoLang$$"
Crash Course in GoLang ◾ 87
// Displaying-strings
fmt.Println("Strings-before-trimming:")
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is:", stry2)
// Trimming given strings
// Using TrimRight() function
rest1 := strings.TrimRight(stry1, "!*")
rest2 := strings.TrimRight(stry2, "$")
// Displaying-results
fmt.Println("\nStrings after trimming:")
fmt.Println("Result 1 is: ", rest1)
fmt.Println("Result 2 is:", rest2)
}
TrimSpace
This method eliminates all white space from the provided string, includ-
ing the leading and following white space.
Syntax:
func TrimSpace(str string) string
Example:
// Program to show how to trim
// the white space from the string
package main
import (
"fmt"
"strings"
)
// main-method
func main() {
// Creating, and initializing the string
// Using shorthand declaration
stry1 := " **Welcome to Home** "
stry2 := " ##This is an example of
GoLang## "
// Displaying-strings
fmt.Println("Strings-before-trimming:")
fmt.Println(stry1, stry2)
// Trimming white space from the given strings
88 ◾ GoLang: The Ultimate Guide
TrimSuffix
The trailing suffix of the string is removed using this procedure. If the
given string does not include the requested suffix string, this function
returns the original text without modification.
Syntax:
func TrimSuffix(str, suffstr string) string
Example:
// Program to show how to
// trim suffix string from the
// given string
package main
import (
"fmt"
"strings"
)
// main-method
func main() {
// Creating, and initializing the string
// Using-shorthand-declaration
stry1 := "Welcome, Home"
stry2 := "This is an example of GoLang"
// Displaying-strings
fmt.Println("Strings-before-trimming:")
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is:", stry2)
// Trimming suffix string from the given
strings
// Using-TrimSuffix()-function
rest1 := strings.TrimSuffix(str1,
"Helloeveryone")
rest2 := strings.TrimSuffix(str2, "Helloo")
Crash Course in GoLang ◾ 89
TrimPrefix
The leading prefix of the string is removed using this procedure. If the input
string does not include the desired prefix string, this function returns the
original string without modification.
Syntax:
func TrimPrefix(str, suffstr string) string
Example:
// program to demonstrate how to trim a prefix
string from a specified string.
package main
import (
"fmt"
"strings"
)
// Main-method
func main() {
// Creating, and initializing the string
// Using-shorthand-declaration
stry1 := "Welcome, Home"
stry2 := "This is an example of GoLang"
// Displaying the strings
fmt.Println("Strings-before-trimming:")
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is: ", stry2)
// Trimming prefix string from the given strings
// Using-TrimPrefix()-function
rest1 := strings.TrimPrefix(str1, "Hello")
rest2 := strings.TrimPrefix(str2, "Everyone")
// Displaying-results
fmt.Println("\nStrings-after-trimming:")
fmt.Println("Result 1 is: ", rest1)
fmt.Println("Result 2 is: ", rest2)
}
90 ◾ GoLang: The Ultimate Guide
Split
This function divides the text into all substrings separated by the provided
separator and returns a slice holding these substrings.
Syntax:
func Split(str, sep string) []string
The string str is utilized here, as is the separator sep. If str does not include
the specified sep and sep is not empty, it will produce a slice of length 1
containing only str. The code will divide after each UTF-8 sequence if the
sep option is not specified. If both str and sep are empty, it will generate
an empty slice.
Example:
// Program to show how to split a string
package main
import (
"fmt"
"strings"
)
// main-function
func main() {
// Creating, and initializing string
stry1 := "Welcome, to, our channel,
Helloeverybody"
stry2 := "My pet name is Bruno"
stry3 := "I love to play cricket"
// Displaying-strings
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is: ", stry2)
fmt.Println("String 3 is: ", stry3)
// Splitting the given strings
Crash Course in GoLang ◾ 91
// Using-Split()-function
rest1 := strings.Split(stry1, ",")
rest2 := strings.Split(stry2, "")
rest3 := strings.Split(stry3, "!")
rest4 := strings.Split("", "Helloeverybody,
hello")
// Displaying result
fmt.Println("\nResult 1 is: ", rest1)
fmt.Println("Result 2 is: ", rest2)
fmt.Println("Result 3 is: ", rest3)
fmt.Println("Result 4 is: ", rest4)
}
SplitAfter
Splits a string into all substrings following each iteration of the given sepa-
rator and returns a slice with these substrings.
Syntax:
func SplitAfter(str, sep string) []string
Example:
// Program to show how to split a string
package main
import (
"fmt"
"strings"
)
// main-function
func main() {
// Creating, and initializing string
stry1 := "Welcome, to online course,
Heyeveryone"
stry2 := "My pet name is fluffy"
stry3 := "I love to bake cake"
// Displaying-strings
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is: ", stry2)
fmt.Println("String 3 is: ", stry3)
// Splitting the given strings
// Using-SplitAfter()-function
92 ◾ GoLang: The Ultimate Guide
SplitAfterN
After each usage of the given separator, split a string into all substrings and
provide a slice comprising these substrings.
Syntax:
func SplitAfterN(str, sep string, m int) []string
Example:
// Program that shows how to split a string
package main
import (
"fmt"
"strings"
)
// main-function
func main() {
// Creating, and initializing string
stry1 := "Welcome, to online session,
Heyeveryone"
stry2 := "My pet name is fluffy"
stry3 := "I love to bake cake"
// Displaying-strings
fmt.Println("String 1 is: ", stry1)
fmt.Println("String 2 is: ", stry2)
fmt.Println("String 3 is: ", stry3)
// Splitting-given-strings
// Using the SplitAfterN() function
rest1 := strings.SplitAfterN(stry1, ",", 2)
Crash Course in GoLang ◾ 93
MAPS
A map is a powerful, innovative, and flexible data structure in the Go com-
puter language. Maps in the GoLang programming language are a collec-
tion of unordered key-value pairs. It’s popular because it provides speedy
lookups and values that can be obtained, modified, or deleted using keys.
Simple
We may create and initialize a map in this manner without using the
make() function:
• Creating a Map: We can simply construct a map by using the fol-
lowing syntax:
// Empty-map
map[KeyType]ValueType{}
// Map with keyvalue pair
map[KeyType]ValueType{key1: value1, ..., keyN:
valueN}
Example:
var mymap map[int]string
A map’s zero value in maps is nil. Therefore, a nil map has no keys.
The compiler will detect a runtime error by adding a key-value pair
into the nil map.
• Using map literals to initialize the map: The easiest approach to
populate a map with data is with map literals; separating the key-
value pair by a colon and the last trailing colon is necessary; other-
wise, the compiler will create an error.
Example:
// Program to show how to
// create, and initialize the maps
package main
import "fmt"
func main() {
// Creating, and initializing the empty map
// Using-var-keyword
var map_1 map[int]int
// Checking if the map is nil or not
if map_1 == nil {
Crash Course in GoLang ◾ 95
fmt.Println("True")
} else {
fmt.Println("False")
}
// Creating, and initializing map
// Using shorthand-declaration
// and using map literals
map_2 := map[int]string{
90: "Hen",
91: "Cow",
92: "Goat",
93: "Cat",
94: "Bird",
}
fmt.Println("Map-2: ", map_2)
}
Syntax:
make(map[KeyType]ValueType, initial_Capacity)
make(map[KeyType]ValueType)
Example:
// Program to show how to
// create, and initialize map
// and using make() function
package main
import "fmt"
func main() {
// Creation of map
// using make() function
var Mymap = make(map[float64]string)
fmt.Println(Mymap)
// As we all know, the make() method always
returns a map that has been initialized
// We can include values in it
Mymap[1.3] = "Nidhi"
96 ◾ GoLang: The Ultimate Guide
Mymap[1.5] = "Sunidhi"
fmt.Println(Mymap)
}
Example:
// Program to show compiler throws
// an error if variable is declared but not used
package main
import "fmt"
// main -unction
func main() {
// calling the function
// function returns two values which
// are assigned to mul and div identifier
mul, div := mul_div(140,1 9)
// using the mul variable only
// compiler will give an error
fmt.Println("140 x 19 = ", mul)
}
// function returning two
// values of the integer type
func mul_div(nm1 int, nm2 int) (int, int) {
// returning-values
return nm1 * nm2, nm1 / nm2
}
Crash Course in GoLang ◾ 97
DEFER KEYWORD
In the Go programming language, defer instructions postpone the execu-
tion of a function, method, or anonymous method until the neighboring
functions return. In other words, deferred function or method call argu-
ments evaluate instantly but do not run until the nearby function returns.
We may create a delayed method, function, or anonymous function using
the defer keyword.
Syntax:
// Function
defer func func-name(parameter_list Type)
return_type{
// Code
}
// Method
defer func (receiver Type) method_name(parameter_
list){
// Code
}
defer func (parameter_list)(return_type){
// code
}()
Example:
// Program to show
// concept of defer statement
package main
import "fmt"
// Function
func mul(d1, d2 int) int {
rest := d1 * d2
fmt.Println("Result: ", rest)
return 0
}
func show() {
fmt.Println("Hello, Everybody")
}
// main-function
func main() {
98 ◾ GoLang: The Ultimate Guide
PANIC IN GoLang
In the Go scripting language, panic, like an exception, happens during
runtime. In other words, panic happens when an unforeseen condition
arises in our Go program, resulting in the program’s execution being ter-
minated. When a specific circumstance exists, such as out-of-bounds array
accesses, panic can occur during runtime, as shown in example.
Syntax:
func panic(v interface{})
Example:
// Program which illustrates concept of panic
package main
import "fmt"
// tmain-function
func main() {
// Creating the array of string type
// Using var-keyword
var myarr [3]string
// The elements are assigned using index
myarr[0] = "HE"
myarr[1] = "Heyyyeverybody"
myarr[2] = "Hello"
// Accessing elements of the array
// Using index-value
fmt.Println("Elements of Array is:")
fmt.Println("Element 1 is: ", myarr[0])
// Program panics because size of the array is 3
Crash Course in GoLang ◾ 99
RECOVER
The recover function in Go is used to manage panic in the same way that
try/catch blocks capture exceptions in languages, such as Java, C#, and
others. It is a built-in function defined in the built-in package of the Go
programming language. This approach is mainly used to re-establish con-
trol of a panicked goroutine. In other words, it addresses the goroutine’s
frantic behavior.
Syntax:
func recover() interface{}
Example:
// program that demonstrates the concept of
recover
package main
import "fmt"
// function is created to handle the
panic occurs in the entry function
// but it does not handle panic occurred in entry
function
// because it called in normal function
func handlepanic() {
if a := recover(); a != nil {
fmt.Println("RECOVER", a)
}
}
// Function
func entry(lang *string, aname *string) {
// Normal-function
handlepanic()
// When value of lang
// is nil it will panic
if lang == nil {
100 ◾ GoLang: The Ultimate Guide
CLOSURES
The Go scripting language has an anonymous function. An anonymous
function can form a closure. A closure is anonymous function that refers
to variables defined outside the function. It is similar to accessing global
variables available before the function’s declaration.
Example:
// Program to show how to create Closure
package main
import "fmt"
func main() {
// Declaring-variable
HFW := 0
// Assigning anonymous
// function to a variable
counter := func() int {
HFW += 1
return HFW
}
fmt.Println(counter())
fmt.Println(counter())
}
Crash Course in GoLang ◾ 101
RECURSION
Recursion is the process through which function, either implicitly or
explicitly, calls itself, and the corresponding function is known as a recur-
sive function. The anonymous function is unique to the Go programming
language. It is a function without a name. It is used to create an inline
function. It is also possible to specify and define anonymous recursive
functions. Recursive anonymous functions, commonly known as recur-
sive function literals, are a type of recursive function.
Syntax:
func(parameter-list)(return-type){
// code call same function
// within function for recursion
// Use return statement only
// if return-type are given.
return
}()
Example:
// Program to show
// how to create recursive Anonymous-function
package main
import "fmt"
func main() {
// Anonymous-function
var recursiveAnonymous func()
recursiveAnonymous = func() {
// Printing message to show the
// function call and iteration
fmt.Println("Anonymous functions could be
recursive.")
// Calling same function
recursively
recursiveAnonymous()
}
// main calling of function
recursiveAnonymous()
}
102 ◾ GoLang: The Ultimate Guide
POINTERS
In the Go computer language or GoLang, pointers are variables that retain
the memory address of another variable. In GoLang, pointers are known
as special variables. Variables are used in the system to keep data at a spec-
ified memory address. Memory addresses are always written in hexadeci-
mal (starting with 0x like 0xFFAAF, etc.).
Example:
// Variables demonstration program
// storing hexadecimal values
package main
import "fmt"
func main() {
// storing hexadecimal values in variables
x := 0xFF
y := 0x9C
// Displaying values
fmt.Printf("Type of variable x is %T\n", x)
fmt.Printf("Value of x in hexadecimal is
%X\n", x)
fmt.Printf("Value of x in decimal is %v\n", x)
fmt.Printf("Type of variable y is %T\n", y)
fmt.Printf("Value of y in hexadecimal is
%X\n", y)
fmt.Printf("Value of y in decimal is %v\n", y)
}
Crash Course in GoLang ◾ 103
Declaring a Pointer
Example: Consider the string pointer as shown below, which can only
hold the memory locations of string variables.
var st *string
Pointer Initialization
To do this, use the address operator to establish a pointer with the memory
address of another variable, as seen in the following example:
// normal variable-declaration
var c = 95
// Initialization of the pointer st with
// memory address of the variable c
var st *int = &c
Example:
// program to show declaration and initialization
package main
import "fmt"
func main() {
// taking normal-variable
var c int = 3998
// declaration of the pointer
104 ◾ GoLang: The Ultimate Guide
var d *int
// initialization of the pointer
d = &c
// displaying-result
fmt.Println("Value stored in c = ", c)
fmt.Println("Address of c = ", &c)
fmt.Println("Value stored in variable d = ", d)
}
Dereferencing a Pointer
The * operator is also known as the dereferencing operator. It is used to
specify the pointer variable and to access the value of a variable to which
the pointer points, a process known as indirecting or dereferencing. The
value at the location is sometimes referred to as the * operator. Let’s look at
an example to help us comprehend this concept:
// Program to illustrate
// the concept of dereferencing a pointer
package main
import "fmt"
func main() {
// using the var keyword
// we are not defining any type with the variable
var x = 328
// taking pointer variable using
// the var keyword without specifying the type
var a = &x
fmt.Println("The Value stored in x = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer variable
a = ", a)
// this is dereferencing a pointer
// using * operator before the pointer
// variable to access value stored at the variable
at which it is pointing
fmt.Println("The Value stored in y(*a) = ", *a)
}
Instead of assigning a new value to the variable, we can alter the value of
the pointer or memory location.
Crash Course in GoLang ◾ 105
Example:
// Program to illustrate the above mentioned concept
package main
import "fmt"
func main() {
// using the var keyword
// we are not defining any type with the variable
var x = 458
// taking pointer variable using
// the var keyword without specifying the type
var a = &x
fmt.Println("The Value stored in y before
changing = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer
variable a = ", a)
// this is dereferencing pointer
// using the * operator before pointer
// variable to access value stored at the
variable at which it is pointing
fmt.Println("The Value stored in x(*a) Before
Changing = ", *a)
// changing the value of x by assigning
// the new value to the pointer
*a = 500
fmt.Println("Value stored in x(*a) after
Changing = ",x)
}
Example: In this case, we can see that we are instantiating a Struct with
the new keyword.
import "fmt"
type emp struct {
name string
empid int
salary int
}
func main() {
// emp1 is a pointer to an instance of emp
// using the new keyword
emp1 := new(emp)
emp1.name = "ABC"
emp1.empid = 2325
emp1.salary = 37000
fmt.Println(emp1)
// emp2 is an instance of emp
var emp2 = new(emp)
emp2.name = "XYZ"
emp2.salary = 40000
fmt.Println(emp2)
}
Pointers to a Function
Pointers are variables in the Go programming language, or GoLang used
to hold the memory address of another variable. We may also pass point-
ers to the function in the same way variables are. There are two ways to
accomplish this.
// dereferencing
*b = 638
}
// the main function
func main() {
// taking normal variable
var y = 200
fmt.Printf("Value of y before function call
is: %d\n", y)
// taking pointer variable and
// assigning the address
// of y to it
var pb *int = &y
// calling tfunction by
// passing the pointer to function
ptf(pb)
Note: The variables and pointers in the preceding programs can also be
declared using the short declaration operator(:=).
Pointer to a Struct
A pointer is a variable that stores the memory address of another variable.
Pointers are also known as special variables in GoLang. The variables are
used to store data in the system at a specific memory address.
A pointer to a struct can also use. In GoLang, a struct is a user-defined
type that allows us to group/combine elements of possibly diverse kinds
into a single type. To utilize a pointer to a struct, use the & operator, also
known as the address operator. GoLang allows programmers to use point-
ers to access the fields of a structure without explicitly dereferencing it.
// Program to illustrate
// the concept of the Pointer to struct
package main
import "fmt"
// taking structure
type Employee struct {
Pointer to Pointer in Go
In the Go programming language or GoLang, pointers are variables that
retain the memory address of another variable. A pointer is a particular
variable that may point to any variable, even another pointer. Essentially,
this looks to be a pointer chain. When we define a pointer to a pointer, the
address of the second pointer is stored in the first pointer. This notion is
also known as double pointers.
Example: In the program below, the pointer pt2 saves the location of
the pointer pt1. Dereferencing pt2, i.e., *pt2 returns the address of vari-
able V or the value of pointer pt1. If we attempt **pt2, you will get the
value of the variable V, which is 200.
// Program to illustrate
// the concept of the Pointer to Pointer
package main
import "fmt"
// the main Function
func main() {
// taking variable
// of the integer type
110 ◾ GoLang: The Ultimate Guide
Comparing Pointers
Pointers are variables in the Go scripting language, or GoLang, holding
another variable’s memory address. In GoLang, pointers are sometimes
referred to as special variables. The variables are used to keep data in the
system at a specified memory address. Memory addresses are always in
hexadecimal format (starting with 0x like 0xFFAAF, etc.).
In the Go scripting language, we may compare two pointers. Two
pointer values are only identical if they point to the same memory address
or are nil. We may compare pointers using the == and != operators pro-
vided by the Go programming language.
== operator
If both pointers refer to the same variable, this function returns true.
Return false if both pointers are pointing to separate variables.
Syntax:
pointer1 == pointer2
Crash Course in GoLang ◾ 111
Example:
// program to show the concept of comparing two
pointers
package main
import "fmt"
func main() {
val1 := 6135
val2 := 926
// Creating, and initializing the pointers
var p1 *int
p1 = &val1
p2 := &val2
p3 := &val1
// Comparing the pointers with each other
// Using == operator
res1 := &p1 == &p2
fmt.Println("Is p1 pointer is equal to p2
pointer: ", res1)
res2 := p1 == p2
fmt.Println("Is p1 pointer is equal to p2
pointer: ", res2)
res3 := p1 == p3
fmt.Println("Is p1 pointer is equal to p3
pointer: ", res3)
res4 := p2 == p3
fmt.Println("Is p2 pointer is equal to p3
pointer: ", res4)
res5 := &p3 == &p1
fmt.Println("Is p3 pointer is equal to the p1
pointer: ", res5)
}
!= operator
This operator returns false if both pointers lead to the same variable.
Return true instead if both pointers refer to different variables.
Syntax:
pointer_1 != pointer_2
112 ◾ GoLang: The Ultimate Guide
Example:
// Program to show the concept of comparing two
pointers
package main
import "fmt"
func main() {
val1 := 12469
val2 := 925
// Creating, and initializing the pointers
var p1 *int
p1 = &val1
p2 := &val2
p3 := &val1
// Comparing pointers with each other
// Using != operator
res1 := &p1 != &p2
fmt.Println("Is p1 pointer not equal to the p2
pointer: ", res1)
res2 := p1 != p2
fmt.Println("Is p1 pointer not equal to the p2
pointer: ", res2)
res3 := p1 != p3
fmt.Println("Is p1 pointer not equal to the p3
pointer: ", res3)
res4 := p2 != p3
fmt.Println("Is p2 pointer not equal to the p3
pointer: ", res4)
res5 := &p3 != &p1
fmt.Println("Is p3 pointer not equal to p1
pointer: ", res5)
}
GoLang STRUCTURES
In GoLang, a structure, also known as a struct, is a user-defined type that
allows us to group/combine parts of possibly divergent kinds into a single
type. A struct is a set of properties/fields that may represent any real-world
entity. This idea is related to classes in general in object-oriented program-
ming. It’s a straightforward class that doesn’t enable inheritance but does
allow for composition.
Crash Course in GoLang ◾ 113
Declaring a structure:
Example:
var x = Address{Name:"Harash",
streetno:"Sitanagar", state:"Punjab", Pin-code:
321429} //city:""
x3 := Address{Name: "Ludhiana"}
fmt.Println("Address3: ", x3)
}
Pointers to a Struct
Pointers are variables in the Go programming language, or GoLang, that
store the memory address of another variable. We may also refer to a
struct, as seen in the following example:
// Program to show a pointer to the struct
package main
import "fmt"
// defining-structure
type Employee struct {
first-name, last-name string
age, salary int
}
func main() {
// passing address of struct-variable empy is a
pointer to Employee struct
empy := &Employee{"Rakshit", "Shardh", 62, 8100}
// (*empy).first-name is the syntax to access
first-name of the empy struct
fmt.Println("First Name:", (*empy).first-name)
fmt.Println("Age:", (*empy).age)
}
Syntax:
type structname1 struct{
// Fields..
}
type structname2 struct{
variablename structname1
}
Crash Course in GoLang ◾ 115
Example:
// Program to show nested-structure
package main
import "fmt"
// Creating-structure
type Author struct {
name string
branchno string
year int
}
// Creating nested-structure
type HR struct {
// structure as field
details Author
}
func main() {
// Initializing fields of the structure
results := HR{
details: Author{"Diksha", "CID", 2022},
}
// Display values
fmt.Println("\nDetails of the Author")
fmt.Println(results)
}
GoLang METHODS
With one exception, Go methods are equivalent to Go functions in imple-
mentation. A receiver parameter is included in the procedure. The receiver
parameter allows the method to access the attributes of the receiver. In this
case, the recipient might be either struct or non-struct. We must maintain
the receiver and receiver type in the same package while writing code.
Furthermore, we are not permitted to write a method whose receiver type
has already been specified in another package, including built-in kinds,
such as int, string, etc. If we attempt, the compiler will generate an error.
Syntax:
func(reciver-name Type) method-name(parameter-
list)(return-type){
// Code
}
116 ◾ GoLang: The Ultimate Guide
Example:
// Program to show method with non-struct type
receiver
package main
import "fmt"
// Type-definition
type data int
// Defining method with the non-struct type
receiver
func (d1 data) multiply(d2 data) data {
return d1 * d2
}
/*
// if we try to run code, compiler will throw
error
func(d1 int)multiply(d2 int)int{
return d1 * d2
}
*/
// the main-function
func main() {
value1 := data(73)
value2 := data(41)
rest := value1.multiply(value2)
fmt.Println("The Final result is: ", rest)
}
Syntax:
func (p *Type) method-name(...Type) Type {
// Code
}
Example:
// Program to illustrate pointer receiver
package main
118 ◾ GoLang: The Ultimate Guide
import "fmt"
// authorstructure
type author struct {
name string
branch string
particles int
}
// Method with the receiver of author type
func (d *author) show(abranch string) {
(*d).branch = abranch
}
// main-function
func main() {
// Initializing-values of author structure
rest := author{
name: "Harsh",
branch: "HRF",
}
fmt.Println("The Author's name is: ", rest.
name)
fmt.Println("The Branch Name(Before) is: ",
rest.branch)
// Creating-pointer
p := &rest
// Calling show-method
p.show("KIH")
fmt.Println("The Author's name is: ", rest.
name)
fmt.Println("The Branch Name(After) is: ",
rest.branch)
}
INTERFACES
The Go Language’s interfaces are distinct from those of other languages.
In Go, an interface is a specific type that expresses a collection of one or
more method signatures. Because the interface is abstract, we cannot cre-
ate an instance of it. However, we are authorized to create an interface
type variable that may be assigned with a concrete type value with the
interface’s needed methods. In other words, the interface is a collection of
methods and a custom type.
Crash Course in GoLang ◾ 119
Example:
// Creating-interface
type myinterface interface{
// Methods
func1() int
func2() float64
}
The type and interface keywords enclose the interface name, whereas curly
brackets enclose the method signatures.
Example:
// Program shows how
// to implement interface
package main
import "fmt"
// Creating-interface
type tank interface {
// Methods
Tarea() float64
Volume() float64
}
type myvalue struct {
radius float64
120 ◾ GoLang: The Ultimate Guide
height float64
}
// Implementing methods of tank interface
func (m myvalue) Tarea() float64
{
return 2*m.radius*m.height +
2*3.14*m.radius*m.radius
}
func (m myvalue) Volume() float64
{
return 3.14 * m.radius * m.radius * m.height
}
// the main-Method
func main() {
// Accessing the elements of tank interface
var tk tank
tk = myvalue{10, 14}
fmt.Println("The Area of tank :", tk.Tarea())
fmt.Println("The Volume of tank:",
tk.Volume())
}
Redundant Functions
Assume we have a pet package (in other languages, a “package” is analo-
gous to a “library”) that contains Dogs and Cats types. Dogs use the Fetch
method, cats use the Purr method, and the Walk and Sit both dogs and
cats use techniques.
package pets
import "fmt"
Crash Course in GoLang ◾ 121
INHERITANCE
Inheritance, which entails inheriting the superclass’s attributes into
the base class, is one of the essential concepts in object-oriented pro-
gramming. Because GoLang lacks classes, inheritance is achieved using
struct embedding. We cannot extend structs directly but must instead
utilize a concept known as composition, in which the struct is used to
construct more objects. As a result, there is no idea of inheritance in
GoLang.
Base structs can be embedded in a child struct in composition, and the
base struct’s methods can be called directly on the child struct, as seen in
the following example:
import (
"fmt"
)
// declaring-struct
type Comic struct{
// declaring struct-variable
Universe string
}
// function to return the universe of comic
func (comic Comic) ComicUniverse() string {
// returns comic-universe
return comic.Universe
}
// declaring struct
type Marvel struct{
// anonymous field,
// this is composition where the struct is
embedded
Comic
}
// declaring-struct
type DC struct{
// anonymous-field
Comic
}
// main-function
func main() {
// creating-instance
cs1 := Marvel{
// child struct can directly access base
struct variables
Comic{
Universe: "MCU",
},
}
// child struct can directly access the base
struct methods printing base method using the child
fmt.Println("Universe is:", cs1.
ComicUniverse())
cs2 := DC{
Comic{
Crash Course in GoLang ◾ 123
Universe : "DC",
},
}
// printing the base method using child
fmt.Println("The Universe is:", cs2.
ComicUniverse())
}
Test-Driven Development
IN THIS CHAPTER
➢➢ Refactoring
➢➢ Error handling
➢➢ Writing tests
In the previous chapter, we covered all the basic concepts of GoLang. This
chapter will discuss Test-Driven Development (TDD) with Go, where we
covered error handling, refactoring, and writing tests.
First, let’s talk about the procedure. TDD is a programming paradigm
that isn’t specific to Go but is quite popular among Go developers.
When developing a program to perform anything (say, multiply two
integers), one must first write a test.
A test is also a program, but it is designed to run another program with
various inputs and examine the outcome. The test ensures that the soft-
ware behaves as expected.
What’s remarkable about the TDD methodology is that we create the
test first before the code is tested (this is frequently referred to as test-first
development). So, why are we doing this?
By developing the test first, we are forced to think explicitly about how
the program should behave and describe those requirements as executable
code with great precision.
Because we’ll be calling our program from the test, we’ll also need to cre-
ate its API. So, contrary to its name, TDD isn’t actually about testing. Instead,
it’s a tool for thinking, a method for creating well-structured systems with
decent APIs. Because we are our own first users, we can quickly identify
when the code isn’t convenient or comfortable to use, and we can improve it.
Let’s examine how we may use that method now that we’ve begun work-
ing on our calculator app.
MAKING Go FILES
A friendly colleague from Texio Instronics has provided us with some Go
code that implements some of the calculator’s functionality and a test for
it, so we don’t have to start from blank. We’ll add that code to our project
folder in this section.
First, create a calculator file with our code editor in the calculator folder.
Then copy and paste the code in the below part:
Don’t worry about knowing all of the code at this point; we’ll go over it in
depth later. For the time being, simply enter this code into the calculator.
Go ahead and save it.
Create a new file called calculator_test.go together with the following:
package calculator_test
import (
"calculator"
"testing"
)
RUN TESTS
Run the following command while still in the calculator folder:
go test
PASS
ok calculator 0.234s
got := calculator.Subtract(6, 3)
if want != got {
t.Errorf("want %f, got %f", want, got)
}
}
Here is the (wrong) code for implementing the Subtract function; paste it
into the calculator .go file, following the Add function:
go test
calculator_test.go:22
Then it invokes the Subtract function with the numbers 6, 3 and saves
the result in another variable obtained:
got := calculator.Subtract(6, 3)
After obtaining this pair of variables, the goal is to compare wish to get
and discover if they vary. If they are, the Subtract function is not function-
ing properly, and the test fails:
if want != got {
t.Errorf("want %f, got %f", want, got)
}
Test (otherwise, Go will not call them when we execute the go test). So
TestMultiply is a wonderful name, isn’t it? Let’s add the new test after
TestSubtract at the end of the file.
Except for the precise inputs and the anticipated return value, TestAdd
and TestSubtract appear remarkably similar. So, to begin, clone one of those
functions, rename it TestMultiply and make the necessary adjustments.
Only the name of the test, the function being called (Multiply instead
of Add, for example), maybe the inputs to it, and the anticipated result of
desire will need to be changed.
Something like this will suffice:
When we’re finished, running the tests should result in the following com-
pilation error:
undefined: calculator.Multiply
Perfect! Now we’re ready to put Multiply into action for real. We’ll know
when we’ve nailed it when our failed test begins to pass. And then we may
come to a halt!
Conflicts Resolve
When GoLand detects issues with our refactoring, it displays a dialog with
a list of conflicts and brief explanations.
Click Continue to dismiss the error and open the preview in the Find
tool window.
To open the conflict items in the Find tool window and deal with them
further, click Show Conflicts in View.
For example, we may try to exclude an entry from refactoring by press-
ing Delete, or we can cancel and return to the editor by clicking Cancel.
Adjust the refactoring choices and click OK on the Code Editing page’s
Refactoring section.
Method of Extraction
This is an approach we commonly use in my programming. It entails
removing a chunk of code that has been grouped by intention and mov-
ing it into a new method. We’ve discovered one compelling reason to use
it: it allows us to divide a big method or function into shorter methods
that group a piece of logic. In most cases, the name of the little method
or function offers a clearer understanding of what that bit of logic is.
The following example displays the before and after effects of this refac-
toring method. My primary objective was to abstract complexity by break-
ing it down into distinct functions.
2 https://wawand.co/blog/posts/four-most-refactoring-techniques-i-use/
Test-Driven Development ◾ 133
Method of Move
After using the extract method refactoring, I sometimes wonder if this
function should belong to this struct or package. Move Method is a
straightforward approach that involves (as the name says) transferring a
method from one struct to another. One way I’ve discovered for deter-
mining if a method should belong to that struct is to see if it accesses the
134 ◾ GoLang: The Ultimate Guide
internals of another struct dependence more than its own. Consider the
following example:
As we can see, the User’s method, BooksTitles, makes greater use of inter-
nal attributes from books (i.e., Title) than the User’s, indicating that this
method should be held by Books rather than the User. Let’s utilize this
refactoring approach to convert this function to the Books type, which
will subsequently be called by the user’s Info method.
The Books type obtains cohesiveness after using this technique since it is
the only one that has control and access to its fields and internal attributes.
Again, this mental process precedes a conscious action, understanding the
repercussions of refactoring.
Even though we don’t see the code within the function, we may imagine
how many operations it does when we see many parameters like this.
Sometimes we notice that such parameters are significantly connected
to one another and are utilized together afterward within the method
where they were declared. This refactoring involves grouping those argu-
ments into a struct, changing the method signature to use that object as
a parameter, and using that object inside the function to handle that cir-
cumstance more object-oriented.
That looks cleaner and provides more information about those parame-
ters. Still, it would necessitate changing all references where this method is
called and creating a new object of type OrderFilter as an argument before
sending it to the function. Again, I try to be extremely deliberate and con-
sider the consequences before doing this modification. When the amount
of influence in our code is modest, I believe this strategy is quite effective.
if strings.Contains(input, ";") {
nm1 := toNumber(input[:strings.Index(input, ";")])
nm2 := toNumber(input[strings.Index(input, ";")+1:])
return toNumber(input)
}
What exactly does that symbol imply? If the response is too vague for us,
we may create a temporary variable and set the value with the hard-coded
character to give it identity and intent.
numberSeparator := ";"
if strings.Contains(input, numberSeparator) {
nm1 := toNumber(input[:strings.Index(input,
numberSeparator)])
nm2 := toNumber(input[strings.Index(input,
numberSeparator)+1:])
return toNumber(input)
}
func main() {
args := os.Args[1:]
inFile := args[0]
inHash := args[1]
hashToCheck := hex.EncodeToString(hash.Sum(nil))
As a result, we’ve already discovered some issues. We’d also like to isolate
the checking logic and develop tests for it.
func main() {
// check for the missing parameters
if len(os.Args) != 3 {
fmt.Println("Error occured: missing-parameters")
// emit non-zero exit code
os.Exit(1)
}
// continue..
}
to that:
hasher := sha256.New()
if _, err := io.Copy(hasher, reader); err != nil {
return false, "", err
}
calculatedHash = hex.EncodeToString(hasher.Sum(nil))
return hash == calculatedHash, calculatedHash, nil
}
Write a Test
We must now develop tests for the code because it is testable.
s := bytes.NewReader(d)
if err != nil {
t.Error(err)
} else if !isValid {
t.Error("hashes don't match", calculatedHash)
}
}
So, in the above code, we generate a byte slice containing the hex codes
0xbeef1010cafe, an io.Reader from it and compute its hash.
140 ◾ GoLang: The Ultimate Guide
Error handling.
Errors in GoLang
Errors indicate that an undesirable circumstance is occurring in our appli-
cation. Assume we wish to establish a temporary directory to store some
files for our program.3 However, the directory creation fails. Because this
is an undesirable circumstance, it is represented with an error.
package main
import (
"fmt"
"ioutil"
)
3 https://gabrieltanner.org/blog/GoLang-error-handling-definitive-guide
Test-Driven Development ◾ 141
func main() {
dir, err := ioutil.TempDir("", "temp")
if err != nil {
return fmt.Errorf("failed to create temp dir
is: %v", err)
}
}
The interface only has one method, Error(), which returns an error mes-
sage as a string. Any type that implements the error interface can be uti-
lized as an error. When displaying the error with techniques such as fmt.
GoLang automatically calls the Error() function when it encounters an
error.
In GoLang, there are several methods for constructing bespoke error
messages, each with its own set of benefits and drawbacks.
The errors.New() method is used to create new errors and takes the error
message as its only argument.
PathError implements the Error() method and hence conforms to the error
interface. Implementing the Error() method now returns a string contain-
ing the PathError struct’s path. We may now use PathError to throw an
error anytime we wish.
Here is a simple example:
package main
import(
"fmt"
)
func main() {
err := throwError()
if err != nil {
fmt.Println(err)
}
}
func main() {
numb, err := divide(200, 0)
if err != nil {
fmt.Printf("error: %s", err.Error())
} else {
fmt.Println("Number: ", numb)
}
}
144 ◾ GoLang: The Ultimate Guide
If the returned error is not nil, it is clear that there is a problem, and we
need to deal with it correctly. Depending on the situation, this may entail
sending a log message to the user, retrying the function until it works, or
closing the application entirely. The only downside is that GoLang does
not need to process returned errors, so we may just ignore handling errors.
Consider the following code as an example:
package main
import (
"errors"
"fmt"
)
func main() {
num2, _ := divide(100, 0)
Defer
A defer statement is a technique for deferring a function by placing it on an
executed stack after the function containing the defer statement has been
completed, either generally by executing a return statement or abnormally
by panicking. Deferred functions are then run in the reverse order that
they were deferred.
As an example, consider the following function:
When the function completes, all delayed functions are run in the oppo-
site order in which they were deferred.
146 ◾ GoLang: The Ultimate Guide
package main
import (
"fmt"
)
func main() {
first()
}
func first() {
defer fmt.Println("first")
second()
}
func second() {
defer fmt.Println("second")
third()
}
func third() {
defer fmt.Println("third")
}
third
second
first
Panic
A panic statement informs GoLang that our code is unable to tackle the
present problem and, as a result, the usual execution flow of our code is
halted. When panic is triggered, all delayed functions are performed, and
the program crashes with a log message including the panic values (typi-
cally an error message) and a stack trace.
GoLang, for example, will panic if an integer is split by zero.
package main
import "fmt"
func main() {
divide(5)
}
func divide(x int) {
fmt.Printf("divide(%d) \n", x+0/x)
divide(x-1)
}
Test-Driven Development ◾ 147
When the division function is invoked with a value of zero, the program
panics, resulting in the results seen below.
We may also panic in our own applications by using the built-in panic
function. A panic should be used only when something unexpected occurs
that the application is unable to manage.
func getArguments() {
if len(os.Args) == 1 {
panic("Not enough-arguments!")
}
}
package main
import (
"fmt"
)
func main() {
accessSlice([]int{11,22,55,66,77,88}, 0)
}
func accessSlice(slice []int, index int) {
fmt.Printf("item %d, value %d \n", index,
slice[index])
defer fmt.Printf("defer %d \n", index)
accessSlice(slice, index+1)
}
item 0, value 1
item 1, value 2
item 2, value 5
item 3, value 6
item 4, value 7
item 5, value 8
defer 5
defer 4
defer 3
defer 2
defer 1
defer 0
panic: runtime error: index out of range [6] with length 6
goroutine 1 [running]:
main.accessSlice(0xc00011df48, 0x6, 0x6, 0x6)
C:/Users/gabriel/articles/GoLang Error handling/
Code/panic/main.go:29 +0x250
main.accessSlice(0xc00011df48, 0x6, 0x6, 0x5)
C:/Users/gabriel/articles/GoLang Error handling/
Code/panic/main.go:31 +0x1eb
main.accessSlice(0xc00011df48, 0x6, 0x6, 0x4)
C:/Users/gabriel/articles/GoLang Error handling/
Code/panic/main.go:31 +0x1eb
main.accessSlice(0xc00011df48, 0x6, 0x6, 0x3)
C:/Users/gabriel/articles/GoLang Error handling/
Code/panic/main.go:31 +0x1eb
main.accessSlice(0xc00011df48, 0x6, 0x6, 0x2)
C:/Users/gabriel/articles/GoLang Error handling/
Code/panic/main.go:31 +0x1eb
Test-Driven Development ◾ 149
Recover
Panics should not terminate the program in some uncommon instances,
but should instead be recovered. For example, if a socket server experiences
an unexpected difficulty, it should notify the clients and subsequently dis-
connect all connections, rather than keeping the clients in the dark about
what happened.
Recover panics by executing the built-in recover function within a
delayed function within the panicking function. The current state of panic
will then end, and the panic error value is returned.
package main
import "fmt"
func main(){
accessSlice([]int{1,2,5,6,7,8}, 0)
}
func accessSlice(slice []int, index int) {
defer func() {
if p := recover(); p != nil {
fmt.Printf("internal error: %v", p)
}
}()
fmt.Printf("item %d, value %d \n", index,
slice[index])
defer fmt.Printf("defer %d \n", index)
accessSlice(slice, index+1)
}
Output:
item 0, value 1
item 1, value 2
item 2, value 5
item 3, value 6
item 4, value 7
item 5, value 8
internal error: runtime error: index out of range [6] with
length 6defer 5
defer 4
defer 3
defer 2
defer 1
defer 0
Error Wrapping
GoLang also allows errors to wrap up other errors, allowing us to provide
additional context to our error messages. This is frequently used to offer
complete details, such as where the issue occurred in our software.
As seen in the following example, we may produce wrapped errors by
using the percent w (%w) option with the fmt.Errorf function.
package main
import (
"errors"
"fmt"
"os"
)
func main() {
err := openFile("non-existing")
if err != nil {
fmt.Printf("error running program: %s \n",
err.Error())
}
}
func openFile(filename string) error {
if _, err := os.Open(filename); err != nil {
Test-Driven Development ◾ 151
As we can see, the program outputs both the new error message generated
by fmt.Errorf and the old error message supplied to the %w flag. GoLang
also can recover a previous error message by unwrapping the error using
errors.Unwrap.
package main
import (
"errors"
"fmt"
"os"
)
func main() {
err := openFile("nonexisting")
if err != nil {
fmt.Printf("error running-program: %s \n",
err.Error())
// Unwrap error
unwrappedErr := errors.Unwrap(err)
fmt.Printf("unwrapped-error: %v \n",
unwrappedErr)
}
}
Casting Errors
We’ll need the means to cast between different error types from time to
time, for example, to access unique information that only that type holds.
The “errors.As” function makes this simple and safe by looking for the first
error in the error chain that meets the error type’s specifications. If there
is no match, the method here returns false.
Let’s have a look at the official errors.As To further understand what is
going on, consider using the documentation example.
package main
import (
"errors"
"fmt"
"io/fs"
"os"
)
func main(){
// Casting error
if _, err := os.Open("non-existing"); err != nil {
var pathError *os.PathError
if errors.As(err, &pathError) {
fmt.Println("Failed at path:",
pathError.Path)
} else {
fmt.Println(err)
}
}
}
package main
import (
"errors"
"fmt"
"io/fs"
"os"
)
func main(){
// Check if error is specific type
if _, err := os.Open("non-existing"); err != nil {
if errors.Is(err, fs.ErrNotExist) {
fmt.Println("file doesn't exist")
} else {
fmt.Println(err)
}
}
}
Beginning
Unlike most other languages I’ve dealt with, Go includes a built-in test run-
ner and a foundation for standard language tools. The simplest approach
to run unit tests for your project is from the command line using a com-
mand like go test. /… This program will find and execute any tests in your
current directory or its subdirectories.
154 ◾ GoLang: The Ultimate Guide
Tests must be written in files distinct from the main package code and
must finish with the suffix_test.go. Starting with func Test identifies a test
function. One of the most basic tests might look like this:
import (
"fmt"
"testing"
"github.com/PullRequestInc/pkg/hello"
)
Unique to Go
If we’re used to creating unit tests in other languages, there are a few dif-
ferences in writing unit tests in Go.
For one thing, we’ll notice in the above example that the testing appears
“crude,” We execute the check ourselves and then return an error mes-
sage. There are no helpers built-in for stuff like t.assertEquals (expected,
actual). This is because Go errs on the side of minimalism, giving only the
essentials required to do a task in one method. This allows the language to
preserve backward compatibility for an extended time while also focusing
on optimizing and enhancing these basic functions over time.
That being said, testify is a fantastic third-party package that is fre-
quently used for executing various sorts of assertions. Testify includes the
Test-Driven Development ◾ 155
assert and need packages – the assert, like the built-in t.Fail will fail the
test on the first failure it sees. Whereas t.Error will just report an error and
continue the test; need will simply report an error and continue the test. We
prefer using the assert package and believe it complements the built-in Go
test tooling and infrastructure well. The fundamental structure of your tests
will remain the same, except for certain assertion helpers that will result in
significantly fewer lines of code. The above example would become:
// hello_test1.go
package hello_test1
import (
"fmt"
"testing"
"github.com/PullRequestInc/pkg/hello"
)
156 ◾ GoLang: The Ultimate Guide
tests := []test{
{input: "world", expected: "hello everyone"},
{input: "pullrequest", expected: "hello
pullrequest"},
}
This is just a simple example, and I’m not really utilizing the setUp or
tearDown functions, but we can see where we can use such chores. On
the other hand, these table-driven tests may be as complex as we want
them to be. We may wish to pass a function as a parameter for some test
scenarios and call distinct functions for tests with a shared setUp and
tearDown.
package hello
Internal tests will always be more brittle than interface tests. Still,
they’re a wonderful method to check internal components are work-
ing properly and are especially beneficial if we utilize TDD.
• When we save, run all of our tests: Go builds and runs rapidly, so
there’s little reason not to run our whole test suite every time we save.
This may be accomplished in Sublime Text by installing GoSublime
and pressing “Cmd+.,5” before adding the following configuration items:
"on_save": [{
"cmd": "gs9o_run_many", "args": {
"commands":[
["clear"],
["sh", "if [ -f onsave.sh ]; then. /onsave.sh;
else gofmt -s -w. / && go build. errors && go test -i
&& go test && go vet && golint ; fi"]
],
"focus_view": false
}
}],
"fmt_cmd": ["goimports"]
Then, before declaring that the results are valid, our test function sim-
ply ranges through the slice, invoking the ‘Fib’ method for each ‘n’:
package mailman
import "net/mail"
type MailMan struct{}
func (ml *MailMan) Send(subject, body string, to
...*mail.Address) {
// some code
}
func New() *MailMan {
return &MailMan{}
}
If the method under test requires a “MailMan” object, our test code can
only call it by giving an actual “MailMan” instance.
A genuine email might be sent every time we run our tests. Now think
about it what would happen if we used the above-mentioned on-save func-
tionality. We’d rapidly irritate our test users or rack up large service costs.
160 ◾ GoLang: The Ultimate Guide
In our test code, we may use a bogus sender and make assertions on the
fields after calling the target function:
This chapter discussed refactoring, error handling, and writing tests with
relevant examples.
Chapter 3
Packaging in GoLang
IN THIS CHAPTER
PACKAGES IN GoLang
In this session, we’ll look at packages in the Go programming language.
When designing applications, it is vital to write maintainable and reusable
code. Go provides modularity and code reusability through its package
ecosystem. Go pushes us to package little bits of software and then utilize
these small packages to assemble larger applications.
Workspace
While we go into Go packages, let’s discuss Workspace structure code.
Go programs are kept in a directory structure known as a workspace. A
workspace is just the home directory for our Go programs. There are three
subdirectories at the root of a workspace:
1. src: This directory contains source files organized as packages. We
will write our Go applications in this directory.
DOI: 10.1201/9781003309055-3 163
164 ◾ GoLang: The Ultimate Guide
Main Package
When we create reusable code, you will create a package as a shared library.
However, while creating executable applications, we will utilize the pack-
age “main” to convert the package into an executable program. The package
“main” instructs the Go compiler to construct the package as an execut-
able application rather than a shared library. The main function in package
“main” will serve as the executable program’s entry point. When you cre-
ate shared libraries, there will be no main package or main function in the
package.
Here’s an example executable program that uses the package main, with
the function main serving as the entry point.
package main
import (
Packaging in GoLang ◾ 165
"fmt"
)
func main(){
fmt.Println("Hello, Everyone")
}
Import Packages
When importing a package into another package, “import” is used.
We imported the package “fmt” into the sample program in Code to
use the method Println. The “fmt” package is part of the Go stan-
dard library. When we import packages, the Go compiler searches
for them in the locations indicated by the environment variables
GOROOT and GOPATH. The GOROOT directory contains pack-
ages from the standard library. The GOPATH location contains
packages that we have written and third-party packages that we have
imported.
go get gopkg.in/mgo.v2
After installing the mgo, add the following import statement to our apps
to reuse the code:
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
Init Function
When writing Go packages, we may include a function called “init” that
is called at the start of the execution period. The init function is useful for
adding initialization logic into a package.
package db
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func init {
// here initialization-code
}
In some instances, we may need to import a package to invoke its init func-
tion, and we do not need to call any of the package’s other methods. If we
import a package but do not use the package identification in the program,
the Go compiler will complain. In this case, we may use a blank identifier
(_) as the package alias name. The compiler will overlook the mistake of
not utilizing the package identifier while still invoking the init function.
package main
import (
_ "mywebapp/libs/mongodb/db"
"fmt"
"log"
)
func main() {
//implementation-here
}
package main
import (
mongo "mywebapp/libs/mongodb/db"
mysql "mywebapp/libs/mysql/db"
)
Packaging in GoLang ◾ 167
func main() {
mongodata :=mongo.Get() //calling the method of
package "mywebapp/libs/mongodb/db"
sqldata:=mysql.Get() //calling the method of
package "mywebapp/libs/mysql/db"
fmt.Println(mongodata )
fmt.Println(sqldata )
}
We’re importing two separate packages from two different locations, but
their names are identical. We may create an alias name for a single package
and use it anytime we need to invoke a method in that package.
Important Considerations
The math package is the primary package in this case, while the
cmplx package is the nested package.
6. Although some packages may have the same name, the route to such
packages is always distinct. For example, both the math and crypto
packages have a rand-named package, but their paths are different,
i.e., math/rand and crypto/rand.
7. In Go programming, why is the main package usually at the top of
the program? Because the main package instructs the go build that
the linker must enable to create an executable file.
Packaging in GoLang ◾ 169
• When constructing a package, we must keep the name brief and con-
cise. Strings, time, flags, and so on are examples of standard library
packages.
• The name of the package should be descriptive and clear.
• Always attempt to avoid using names already in use or those used for
local relative variables.
• The package’s name is usually written in the singular form. Several
packages are named plural to prevent keyword conflicts, such as
strings, bytes, buffers, etc.
• Always avoid package names with preexisting meanings. As an
example:
// Program to illustrate
// the concept of packages
// Package declaration
package main
// Importing the multiple packages
import (
"bytes"
"fmt"
"sort"
)
func main() {
// Creating and initializing the slice
// Using the shorthand declaration
slice_1 := []byte{'*', 'H', 'e', 'l', 'l',
'o', 'f',
'o', 'r', 'W', 'o', 'r', 'k', 's', '^',
'^'}
slice_2 := []string{"hel", "lo", "for", "wor",
"ks"}
// Displaying the slices
fmt.Println("Original-Slice:")
fmt.Printf("Slice 1 : %s", slice_1)
170 ◾ GoLang: The Ultimate Guide
Code Exported
We might have noticed the declarations in the greet.go file we called were
all uppercase. Go, unlike other languages, does not have the idea of public,
private, or protected modifiers. Capitalization governs external visibility.
Types, variables, functions, and that begin with a capital letter are publicly
accessible outside of the current package. A symbol that can be seen out-
side of its container is termed exported.
If we add a new reset method to Octopus, we may call it from the wel-
come package but not from our main.go file, which is not part of the greet
package:
package greet
import "fmt"
var Shark = "Rammy"
type Octopus struct {
Name string
Color string
}
func (o Octopus) String() string {
return fmt.Sprintf("Octopus's name is %q and
the color %s.", o.Name, o.Color)
}
func (o *Octopus) reset() {
o.Name = ""
o.Color = ""
}
func Hello() {
fmt.Println("Hello, Everyone")
}
Packaging in GoLang ◾ 171
package main
import (
"fmt"
"github.com/gopherguides/greet"
)
func main() {
greet.Hello()
fmt.Println(greet.Shark)
oct := greet.Octopus{
Name: "Tessa",
Color: "White",
}
fmt.Println(oct.String())
oct.reset()
}
package greet
import "fmt"
var Shark = "Rammy"
type Octopus struct {
Name string
Color string
}
func (o Octopus) String() string {
return fmt.Sprintf("The octopus's name is %q
and is the color %s.", o.Name, o.Color)
}
func (o *Octopus) Reset() {
o.Name = ""
o.Color = ""
}
func Hello() {
fmt.Println("Hello, Everyone")
}
172 ◾ GoLang: The Ultimate Guide
package main
import (
"fmt"
"github.com/gopherguides/greet"
)
func main() {
greet.Hello()
fmt.Println(greet.Shark)
oct := greet.Octopus{
Name: "Tessa",
Color: "White",
}
fmt.Println(oct.String())
oct.Reset()
fmt.Println(oct.String())
}
$ go run main.go
Awesome Go
Before we get into the libraries, we’d like to introduce you to Awesome
Go, a constantly updated and selected collection of Go libraries and other
resources. We should check in every now and then to see what’s new.
GoLang-Set
Go contains arrays, slices, and maps but no fixed data structure. Use a map
of bools to simulate a set, but it’s preferable to have a real data type with
Packaging in GoLang ◾ 173
package main
import (
"fmt"
"github.com/deckarep/GoLang-set"
)
func main() {
basicColors := mapset.NewSet()
basicColors.Add("Yellow")
basicColors.Add("White")
basicColors.Add("Grey")
if basicColors.Contains("Grey") {
fmt.Println("Yay! 'Grey' is a basic color")
} else {
fmt.Println("What a disappointment! 'Grey' is not a
basic color")
}
if basicColors.Contains("Pink") {
fmt.Println("Yay! 'Pink' is a basic color")
} else {
fmt.Println("What a disappointment! 'Pink' is not a
basic color")
}
}
Output:
It is worth noting that the package name is “mapset.” Aside from the fun-
damentals, we may execute all set operations such as union, intersection,
and difference. We may also iterate through the values we’ve chosen:
package main
import (
"fmt"
174 ◾ GoLang: The Ultimate Guide
"github.com/deckarep/GoLang-set"
)
func main() {
basicColors := mapset.NewSet()
basicColors.Add("White")
basicColors.Add("Brown")
basicColors.Add("Grey")
otherColors := mapset.NewSetFromSlice([]interface{}
{"Pink", "Black", "Indigo", "Blue"})
rainbowColors := basicColors.Union(otherColors)
Color
Let’s keep the color scheme going. When designing command-line applica-
tions, use colors to emphasize important messages or distinguish between
faults, successes, and warnings.
The color package allows you to add color to our applications easily. It
employs ANSII escape codes and is also compatible with Windows! Here’s
a simple example:
package main
import (
"github.com/fatih/color"
)
func main() {
color.Red("Carrot is Orange ")
color.Blue("Sky is blue")
}
The color package allows us to blend colors with backdrop colors, use
styles like strong or italic, and splatter color over non-color output.
Packaging in GoLang ◾ 175
package main
import (
"github.com/fatih/color"
"fmt"
)
func main() {
minion := color.New(color.FgBlack).Add(color.BgYellow).
Add(color.Bold)
minion.Println("Minion says: banana!")
m := minion.PrintlnFunc()
m("We want another banana!")
Now
Now is a very basic package that acts as a wrapper for the standard time
package, making it easy to interact with the various date and time con-
structions centered around the current time.
We can, for example, retrieve the start of the current minute or the end
of the Sunday closest to the present time. Here’s an example of how to
utilize “now”:
package main
import (
"github.com/jinzhu/now"
"fmt"
)
func main() {
fmt.Println("All beginnings….")
fmt.Println(now.BeginningOfMinute())
fmt.Println(now.BeginningOfHour())
fmt.Println(now.BeginningOfDay())
fmt.Println(now.BeginningOfWeek())
fmt.Println(now.BeginningOfMonth())
176 ◾ GoLang: The Ultimate Guide
fmt.Println(now.BeginningOfQuarter())
fmt.Println(now.BeginningOfYear())
Output:
We may also parse dates and timings and even create our own forms
(which will require updating the known formats). The Now type incorpo-
rates time. We have time so that you can utilize it all. Apply time methods
directly to now objects.
Gen
The gen tool creates code for you, specifically type-aware code that attempts
to bridge the gap left by Go’s lack of templates and generics.
We add a specific comment to our types, and gen creates source files to
include in our project. There is no runtime magic. Let’s look at the follow-
ing example, which is of the annotated type.
// +gen slice:"Where,Count,GroupBy[int]"
type Person struct {
Names string
Ages int
}
package main
The code includes LINQ-like methods for working with the PersonSlice
type. It’s straightforward to grasp and well-documented.
Here’s how we put it to use. A PersonSlice is defined in the main func-
tion. The age() function chooses the age field from the Person parameter.
178 ◾ GoLang: The Ultimate Guide
The produced GroupByInt() method takes the age() function and groups
the persons in the slice by age.
package main
import (
"fmt"
)
// +gen slice:"Where,Count,GroupBy[int]"
type Person struct {
Name string
Age int
}
func main() {
people := PersonSlice {
{"Jimy", 44},
{"Hane", 28},
{"Lyle", 21},
}
groupedByAge := people.GroupByInt(age)
fmt.Println(groupedByAge)
}
Output:
Gorm
Go is noted for its austerity. Database programming is no exception. The
majority of popular Go DB libraries are rather low-level. Gorm introduces
the realm of object-relational mapping to Go by including the following
features:
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
func main() {
db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
panic("failed to connect the database")
}
defer db.Close()
// Migrate schema
db.AutoMigrate(&Product{})
// Create
db.Create(&Product{Code: "L1212", Price: 1200})
180 ◾ GoLang: The Ultimate Guide
// Read
var product Product
db.First(&product, 1) // find product with the id 1
db.First(&product, "code =? ", "L1212")
// Delete – delete-product
db.Delete(&product)
Goose
Managing the schema is one of the most critical jobs when dealing with
relational databases. Changing the database schema is seen as a “danger-
ous” modification in certain businesses. If necessary, the goose package
allows us to perform schema modifications and even data migrations. We
may go back and forth by goose up and goose down. But keep an eye on
our data and make sure it doesn’t get lost or damaged.
Goose works by versioning our schema and utilizing migration files for
each schema. SQL commands or Go commands are used in the migration
files. An example of a SQL migration file that adds a new table is shown below:
-- +goose Up
CREATE TABLE person (
id int NOT NULL,
names text,
ages int,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE person;
Glide
Glide is a Go package manager. Many programs with conflicting depen-
dencies may run under a single GOPATH. The answer is for each applica-
tion to keep track of its own vendor directory of package dependencies.
Glide assists with this task.
Glide has the following characteristics:
• Aliasing packages are supported (e.g., for working with GitHub forks).
• Remove the requirement for import statements to be munged.
• Work using all of the available tools.
• All of the VCS tools that Go offers are supported (git, bzr, hg, svn).
• Custom local and global plugins are supported.
• For optimal speed, use repository caching and data caching.
• Flatten dependencies, resolve version discrepancies, and prevent
including a package more than once.
• In our version control system, we may manage and install dependen-
cies on-demand or vendored.
Ginkgo
Ginkgo is a testing framework for Behavior Driven Development (BDD).
It allows us to write your tests in a syntax similar to English, allowing less
technical individuals to analyze the tests and ensure that they meet the
business requirements.
This form of a test specification is also popular among developers.
It connects with Go’s built-in testing package and is frequently used in
conjunction with Gomega. An example of a Ginkgo + Gomega test is as
follows:
Etcd
Etcd is a trustworthy distributed Key-Value store. The server is written in
Go, and the Go client communicates with it through gRPC.
It focuses on the following aspects:
func test_get() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: dialTimeout,
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
NSQ
NSQ is a fantastic distributed queue. It has served me well as the main
building component for large-scale distributed systems. Here are some of
its characteristics:
package main
import (
"github.com/bitly/go-nsq"
)
func main() {
config := nsq.NewConfig()
p, _ := nsq.NewProducer("127.0.0.1:4150", config)
p.Publish("topic", []byte("messages"))
p.Stop()
}
184 ◾ GoLang: The Ultimate Guide
Docker
Docker is now a household name. We might be surprised to learn that
Docker is built into Go. We don’t usually use Docker in our work, but it’s
an important project that deserves to be acknowledged as a very successful
and popular Go project.
Kubernetes
Kubernetes is a cloud-native container orchestration tool that is free source.
It is another massively distributed system written in Go. We recently pub-
lished a book, called Mastering Kubernetes, in which we go into great detail
about the most advanced features of Kubernetes. Kubernetes is incredibly
versatile from the standpoint of a Go developer, and it can be extended and
customized via plugins.
DEPENDENCY MANAGEMENT
Go employs a unique approach to dependency management in that it is source-
based rather than artifact-based. Packages in an artifact-based dependency man-
agement system are made up of artifacts created from source code and are kept
in a repository system distinct from the source code. Many NodeJS packages, for
example, utilize npmjs.org as a package repository and github.com as a source
repository. Similarly, on the other hand, packages in Go are source code, and
publishing a package does not require the creation of artifacts or establishing a
separate repository. Go packages must be kept in a VCS server’s version control
repository. Dependencies are retrieved either directly from their VCS server or
through an intermediate proxy, which retrieves them from their VCS server.
Versioning
Modules and first-class package versioning are added to the Go ecosys-
tem with versioning Go 1.11. Previously, Go lacked a well-defined system
for version control. While third-party version management solutions were
available, the native Go experience did not allow versioning.
Semantic versioning is used in Go Modules. A module’s versions are
specified as version control system (VCS) tags that represent legitimate
semantic versions prefixed with v. To release version 1.0.0 of gitlab.com/
my/project, for example, the developer must generate the Git tag v1.0.0.
Other than 0 and 1, the module name is prefixed with/vX, where X is
the major version. For example, gitlab.com/my/project/v2.0.0 must be
titled and imported as gitlab.com/my/project/v2.1
1 https://docs.gitlab.com/ee/development/go_guide/dependencies.html
Packaging in GoLang ◾ 185
Modules
In GoLang, a module is a grouping of related packages versioned as one
unit. We may use Go Modules to implement specific dependency needs
and create repeatable builds for multiple environments. It dramatically
simplifies dependency management in GoLang.
To begin utilizing Modules in your project, just run the following
command (this is relevant if our project currently uses version control):
go mod init
For instance, here’s how you may begin utilizing modules in our project:
When we run the above command, it will create a go.mod module config
file in the root directory of our project. The module and Go version infor-
mation is included in the file.
module github.com/Alfrick/Go-Test
go 1.14
The file specifies the project’s needs and includes all required depen-
dencies, similar to the “package.json” file used in “Node.js” dependency
management.
Installing Dependencies
We may now incorporate new dependencies into our codebase after
starting our project to begin utilizing Go Modules.
To install dependencies in GoLang, use the go get command, automati-
cally updating the go.mod file.
Here’s an illustration:
go get github.com/lib/pq
go get github.com/lib/pq@master
go get github.com/lib/pq@v1.8.0
After we execute the command, our go.mod file should look like this:
module github.com/Alfrick/Go-Test
go 1.14
require github.com/lib/pq v1.8.0 // indirect
Packaging in GoLang ◾ 187
// main.go
package main
import (
"github.com/lib/pq"
)
func main() {
pq.Load()
}
go mod tidy
Because the go.mod file includes all of the information required for
repeatable builds, it’s critical to execute the go mod tidy command after
making any changes to our code. It will verify that your module file is cor-
rect and tidy, especially before each change.
// main.go
package main
import (
"github.com/lib/pq"
"github.com/subosito/gotenv"
)
func main() {
pq.Load()
log.Println(os.Getenv("APP_ID"))
}
The program will automatically retrieve the missing package and add it to
our go.mod file before our project is constructed when we run go build.
The modified go.mod file is available here:
module github.com/Alfrick/Go-Test
go 1.14
require (
github.com/lib/pq v1.8.0
github.com/subosito/gotenv v1.2.0
)
go get github.com/lib/pq
go get github.com/lib/pq@v1.8.0
go get -u github.com/lib/pq
Listing Dependencies
Run the below-given command to see a list of the current module (also
known as the main module) and all its dependencies:
go list -m all
Naming
Except for the standard library, the name of a module or package must be
of the form (sub.)*domain.tld(/path)*. This is comparable to, but not the
Packaging in GoLang ◾ 191
same as, a URL. The package name lacks a scheme (such as https://) and
cannot include a port number. The name example.com:8443/my/package
is invalid.
Fetching Packages
The following was the procedure for getting a package:
Handling Concurrency
IN THIS CHAPTER
➢➢ Concurrency or parallelism
➢➢ Goroutines
➢➢ Shared resources
CONCURRENCY
Concurrency refers to a program’s capacity to do numerous tasks simul-
taneously. This refers to a program with two or more jobs that simulta-
neously execute independently but are still part of the same program.
Concurrency is critical in modern software because it allows separate sec-
tions of code to be executed as quickly as feasible without disrupting the
overall flow of the program.
In GoLang language, concurrency refers to the ability for functions to
operate independently of one another. A goroutine is a function that may
execute in parallel with other functions. When you define a function as
a goroutine, it is viewed as an independent unit of scheduled work and
then runs on an available logical processor. The GoLang runtime sched-
uler handles all goroutines that are formed and need processor time. To
run goroutines, the scheduler ties operating system threads to logical
DOI: 10.1201/9781003309055-4 193
194 ◾ GoLang: The Ultimate Guide
Concurrency and parallelism come into play when looking for multitask-
ing, and they are frequently used interchangeably; concurrent and parallel
refer to similar but distinct aspects.
Concurrency is the ability to manage many tasks at the same time. This
suggests we’re attempting to manage many jobs at once in a short amount
of time. We will, however, only be executing one activity at a time. This is
common in programs where one job is waiting, and the software decides
to drive another task during the idle period. It is a feature of the issue
domain in which our application must handle several concurrent events.
Parallelism is the practice of performing many things at the same time.
This implies that even if we have two processes running concurrently,
there are no gaps in between. It is a feature of the solution domain in which
we wish to speed up our program by processing separate parts of the issue
in parallel.
A concurrent program contains many logical control threads. These
threads may or may not run concurrently. A parallel program might theo-
retically run faster than a sequential program since it does various sections
of the calculation simultaneously (in parallel). It may or may not contain
more than one logical control thread.
Handling Concurrency ◾ 195
package main
import (
"fmt"
"sync"
"time"
)
const (
sleeping = iota
checking
cutting
)
// Barber-goroutine
// Checks for the customers
// Sleeps - wait for the wakers to wake him up
func barber(b1 *Barber, wr chan *Customer, wakers chan
*Customer) {
for {
b1.Lock()
defer b1.Unlock()
b1.state = checking
b1.customer = nil
wg.Done()
b1.customer = nil
}
// customer-goroutine
// just fizzles out if it's full, otherwise customer
// is passed along to channel handling it's haircut etc
func customer(c1 *Customer, b1 *Barber, wr chan<-
*Customer, wakers chan<- *Customer) {
// arrive
time.Sleep(time.Millisecond * 50)
// Check on barber
B1.Lock()
fmt.Printf("The Customer %s checks %s barber | room: %d,
w %d - customer: %s\n",
c1, stateLog[b1.state], len(wr), len(wakers),
b1.customer)
switch b1.state {
case sleeping:
select {
case wakers <- c1:
default:
select {
case wr <- c1:
default:
wg.Done()
}
}
case cutting:
select {
case wr <- c1:
default: // Full waiting room, and leave shop
wg.Done()
}
case checking:
panic("Customer shouldn't check for Barber when Barber
is Checking the waiting room")
}
b1.Unlock()
}
func main() {
b1 := NewBarber()
b1.name = "Jocky"
WaitingRoom := make(chan *Customer, 5) // 5-chairs
Wakers := make(chan *Customer, 1) // Only-one waker
at time
go barber(b1, WaitingRoom, Wakers)
198 ◾ GoLang: The Ultimate Guide
time.Sleep(time.Millisecond * 100)
wg = new(sync.WaitGroup)
n := 10
wg.Add(10)
// Spawn customers
for i := 0; i < n; i++ {
time.Sleep(time.Millisecond * 50)
c1 := new(Customer)
go customer(c1, b1, WaitingRoom, Wakers)
}
wg.Wait()
fmt.Println("No more customers for day")
}
package main
import (
"flag"
"fmt"
"log"
"os"
"runtime"
"runtime/pprof"
)
Handling Concurrency ◾ 199
// Producer-definition
type Producer struct {
msgs *chan int
done *chan bool
}
func main() {
// profile flags
cpuprofile := flag.String("cpuprofile", "", "write cpu
profile to 'file'")
memprofile := flag.String("memprofile", "", "write memory
profile to 'file'")
200 ◾ GoLang: The Ultimate Guide
flag.Parse()
// CPU Profile
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal("couldn't create CPU profile: ", err)
}
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("couldn't start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}
// Memory Profile
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal("couldn't create memory profile: ", err)
}
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err)
}
f.Close()
}
}
Handling Concurrency ◾ 201
Go Concurrent Programming
Concurrent programming uses the many processor cores seen in
most modern computers. The idea has been around for a long time,
even when the single Core had one core. Many computer languages,
including C/C++, Java, and others, use many threads to achieve some
concurrency.
A single thread is a small set of instructions scheduled to be executed
sequentially. We may think of it as a task within a larger enterprise.
func name(){
// statement
}
// using the go keyword as the prefix of a function
call
go name()
Example:
// Program to illustrate the concept of Goroutine
package main
import "fmt"
func display(str string) {
for g := 0; g < 5; g++ {
fmt.Println(str)
}
}
func main() {
// Calling-Goroutine
go display("Welcomehome")
// Calling-normal-function
display("Helloeveryone")
}
MULTIPLE Goroutines
In our program, a Goroutine is a function or procedure that runs inde-
pendently and simultaneously with other Goroutines. In other terms, a
Goroutine is any continuously running activity in the Go programming
language. We may have several goroutines in a single program in the Go
computer language. We may create a goroutine by prefixing the function
or method call with the go keyword, as seen below:
func name(){
// statement(s)
}
Handling Concurrency ◾ 203
Example:
// Program to demonstrate the Multiple Goroutines
package main
import (
"fmt"
"time"
)
// For goroutine 1
func Aname() {
arr1 := [4]string{"Shreya", "Disha", "Kartik",
"Mira"}
for t1 := 0; t1 <= 3; t1++ {
time.Sleep(160 * time.Millisecond)
fmt.Printf("%s\n", arr1[t1])
}
}
// For goroutine 2
func Aid() {
arr2 := [4]int{500, 102, 209, 901}
for t2 := 0; t2 <= 3; t2++ {
time.Sleep(500 * time.Millisecond)
fmt.Printf("%d\n", arr2[tk2])
}
}
// main-function
func main() {
fmt.Println("!Main Go-routine Start!")
// calling-Goroutine 1
go Aname()
// calling-Goroutine 2
go Aid()
time.Sleep(3100 * time.Millisecond)
fmt.Println("\n!Main Go-routine End!")
}
204 ◾ GoLang: The Ultimate Guide
will compete for such locks to access the data. In some circumstances,
using thread-safe data structures like Python’s Queue makes this easier.
Concurrency primitives in Go, such as goroutines and channels, offer
an attractive and unique way of constructing concurrent software. Instead
of employing explicit locks to manage access to shared data, Go supports
the use of channels to transfer data references across goroutines. This
method assures that only one goroutine has access to the data at any one
moment. The idea is summed up in the document Effective Go:
Instead of communicating by sharing memory, communicate by shar-
ing memory.
Take, for example, a program that polls a list of URLs. In a conventional
threading context, data may be structured as follows:
if r1 != nil {
r1.polling = true
}
res.lock.Unlock()
if r1 == nil {
continue
}
// poll URL
// update Resource's polling and lastPolled
res.lock.Lock()
r1.polling = false
r1.lastPolled = time.Nanoseconds()
res.lock.Unlock()
}
}
The delicate logic from the previous example has vanished, and our
Resource data structure no longer holds accounting data. In reality, all
that’s left are the essentials. This should give us an idea of how powerful
these simple language features are.
Handling Concurrency ◾ 207
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func credit() {
for c := 0; c < 5; c++ {
mutex.Lock()
balance += 120
time.Sleep(time.Duration(rand.Intn(100))
* time.Millisecond)
fmt.Println("After crediting, balance:", balance)
mutex.Unlock()
}
}
func debit() {
for c := 0; c < 5; c++ {
mutex.Lock()
balance -= 120
time.Sleep(time.Duration(rand.Intn(100))
* time.Millisecond)
fmt.Println("After debiting, balance:", balance)
mutex.Unlock()
}
}
func main() {
balance = 220
fmt.Println("Initial balance:", balance)
go credit()
go debit()
fmt.Scanln()
}
Handling Concurrency ◾ 209
The Mutex object’s Lock() and Unlock() procedures allow you to mark the
beginning and conclusion of a vital section and prevent several goroutines
from accessing the same resource. So, while one Goroutine has the lock,
the other Goroutine has no choice except to wait till Unlock() is called.
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func credit() {
for c := 0; c < 10; c++ {
// adds 120 to balance atomically
atomic.AddInt64(&balance, 100)
time.Sleep(time.Duration(rand.Intn(120))
* time.Millisecond)
}
}
func debit() {
for c := 0; c < 5; c++ {
// deducts -120 from balance atomically
atomic.AddInt64(&balance, -120)
time.Sleep(time.Duration(rand.Intn(120))
* time.Millisecond)
}
}
210 ◾ GoLang: The Ultimate Guide
func main() {
balance = 220
fmt.Println("Initial balance:", balance)
go credit()
go debit()
fmt.Scanln()
Concurrency Issues
Concurrency Disadvantages
Benefits of Concurrency
1 https://www.geeksforgeeks.org/concurrency-in-operating-system/
212 ◾ GoLang: The Ultimate Guide
IN THIS CHAPTER
➢➢ Flow control
➢➢ Types
➢➢ Modules and packages
➢➢ Error handling
➢➢ Comparing keywords and syntax
➢➢ Functions
We discussed handling concurrency in the last chapter, and in this
chapter, we will explore flow control, types, modules, and packages.
Furthermore, we will cover error handling and keyword and function
comparison.
FLOW CONTROL
There is just one loop in the Go programming language, and it is a for
loop. A for loop in GoLang is a type of repetition control structure that
enables us to create a loop that will run a set number of times. In the
Syntax:
for initialization; condition; post{
// statements
}
Here,
The initialization statement is optional and is executed before the
for loop starts. An introductory statement, such as variable declara-
tions, increment or assignment instructions, or function calls, always
includes an initialization statement.
The condition statement includes a boolean expression evaluated
at the beginning of each loop iteration. If the conditional statement’s
value is true, the loop runs.
The post statement follows the for loop body. The condition state-
ment is re-evaluated after the post statement; if the conditional state-
ment’s value is false, the loop is ended.
Example:
// Program to show the use of simple for loop
package main
import "fmt"
// main-function
func main() {
// for loop
// This loop starts when d = 0
// executes till d<5 condition is true
// post statement is d++
for d := 0; d < 5; d++{
fmt.Printf("hello-everyone\n")
}
}
GoLang for JavaScript Developers ◾ 215
2. For loop as infinite loop: A for loop may be used as an endless loop
by removing all three expressions from it. When a user does not
add a condition statement in a for loop, the condition statement is
assumed to be true, and the loop enters an infinite loop.
Syntax:
for
{
// Statements
}
Example:
// Program to show the use of an infinite loop
package main
import "fmt"
// main-function
216 ◾ GoLang: The Ultimate Guide
func main() {
// infinite-loop
for {
fmt.Printf("Hello-everyone\n")
}
}
3. while for loop: A while loop can be used in place of a for loop. This
loop is performed until the condition stated is met. When the value
of the specified condition is false, the loop is ended.
Syntax:
for condition{
// statements
}
Example:
// Program to demonstrate for loop as while Loop
package main
GoLang for JavaScript Developers ◾ 217
import "fmt"
// main-function
func main() {
// while loop for loop executes till
// d < 3 condition is true
d:= 0
for d < 3 {
d += 2
}
fmt.Println(d)
}
4. Simple range in for loop: The range can also be used to create a loop.
Syntax:
for c, d:= range rvariable{
// statements
}
The iteration values are saved in the variables c and d. Iteration vari-
ables are another name for them.
The second variable, d, is optional.
The range expression is evaluated once before the loop begins.
Example:
// A program that demonstrates the use of a basic
range loop
package main
import "fmt"
// main-function
func main() {
// Here rvariable is array
rvariable:= []string{"HEW", "Hey",
"Heyeveryoneworld"}
// c and d stores value of rvariable
// c store index number of the individual
string and
// d store individual string of given array
for c, d:= range rvariable {
fmt.Println(c, d)
}
}
218 ◾ GoLang: The Ultimate Guide
5. Using a for loop for strings: A for loop can run over the Unicode
code points in a text.
Syntax:
for index, chr:= range str{
// Statement..
}
Example:
// A program to demonstrate the use of a for loop
with a string
package main
import "fmt"
// main-function
func main() {
// String as range in for loop
for c, d:= range "CcdXY" {
fmt.Printf("The Index number of %U is
%d\n", d, c)
}
}
6. For maps: A for loop can iterate through the key and value pairs in
the map.
Syntax:
for key, value := range map {
// Statement..
}
Example:
// Maps are used in this program to demonstrate
the use of loops.
package main
import "fmt"
// main-function
func main() {
// using-maps
mmap := map[int]string{
22:"Piiks",
GoLang for JavaScript Developers ◾ 219
33:"POP",
44:"PiiksofPiiks",
}
for key, value:= range mmap {
fmt.Println(key, value)
}
}
7. For channel: A for loop can cycle over the channel’s successive data
until the channel is terminated.
Syntax:
for item := range Chnl {
// statement..
}
Example:
// A code to demonstrate the use of a loop using
channel
package main
import "fmt"
// main-function
func main() {
// using-channel
chnl := make(chan int)
go func(){
chnl <- 200
chnl <- 2000
chnl <- 20000
chnl <- 200000
close(chnl)
}()
for d:= range chnl {
fmt.Println(d)
}
}
objects generated within the scope are also destroyed. The Go program-
ming language offers three types of loop control statements:
• Break
• Goto
• Continue
Break Statement
The break statement is used to end the loop or statement it presents. If they
are present, the control is then passed to the statements that follow the
break statement. If the break statement is included in the nested loop, it
only stops the loops that contain the break statement.
import "fmt"
// Main function
func main() {
for c:=0; c<5; c++{
fmt.Println(c)
Goto Statement
This statement is used in the program to transfer control to the labeled state-
ment. The label serves as valid identification and is inserted immediately before
the statement from which control is transferred. Programmers rarely use Goto
statements because they make tracking the program’s control flow harder.
import "fmt"
func main() {
var y int = 0
Continue Statement
This statement is used to ignore the execution portion of the loop if a given
condition is met. The control is then returned to the beginning of the loop.
It skips the following statements and proceeds with the next loop iteration.
// Go program to illustrate
// the use of continue statement
package main
import "fmt"
func main() {
var y int = 0
TYPES
Basic Types
Data types specify the data types that can store in a valid Go variable. The
Go language divides types into various categories, which are as follows:
This section will go through the fundamental data types in the Go pro-
gramming language. The Basic Data Types are even further split into three
subcategories, as follows:
• Numbers
• Booleans
• Strings
Numbers
In Go, numbers are divided into three subcategories, which are as follows:
• Integers: The Go programming language supports both signed and
unsigned numbers in four different sizes, as shown in the following
table. Signed integers are indicated by int, whereas unsigned integers
are denoted by uint.
Example:
// Integers are used in this program to
demonstrate their use
package main
import "fmt"
func main() {
// 8bit unsigned int using
var X uint8 = 221
fmt.Println(X, X-3)
// Using the 16bit signed int
var Y int16 = 32676
fmt.Println(Y+2, Y-2)
}
Example:
// illustrate the use of floating-point numbers
package main
import "fmt"
func main()
{
c := 22.46
d := 35.88
// Subtract of two floating-point number
e := d-c
// Display the result
fmt.Printf("The Result is: %f", e)
224 ◾ GoLang: The Ultimate Guide
Example:
// Illustrate use of the complex numbers
package main
import "fmt"
func main() {
var c complex128 = complex(17, 2)
var d complex64 = complex(9, 2)
fmt.Println(c)
fmt.Println(d)
// Display the type
fmt.Printf("The type of c is %T and "+
"the type of d is %T", c, d)
}
Booleans
The boolean data type only represents two values: true or false.
Boolean values are neither inherently nor explicitly changed to any
other type.
Example:
// A program that demonstrates the use of Boolean
package main
GoLang for JavaScript Developers ◾ 225
import "fmt"
func main() {
// variables
strng1 := "PiiksofPiiks"
strng2:= "piiksofpiiks"
strng3:= "PiiksofPiiks"
result1:= strng1 == strng2
result2:= strng1 == strng3
// Display the result
fmt.Println( result1)
fmt.Println( result2)
// Display type of the
// result1 and result2
fmt.Printf("The type of result1 is %T and "+
"the type of result2 is %T",
result1, result2)
}
Strings
A string data type comprises a sequence of Unicode code points. In other
words, a string is a collection of immutable bytes, which means that it can-
not change once it is produced. A string can contain any human-readable
data, including zero-value bytes.
Example:
// A program that demonstrates the use of strings.
package main
import "fmt"
func main()
{
// strng variable stores strings
strng := "PiiksofPiiks"
// Display length of the string
fmt.Printf("The Length of the string is:%d",
len(strng))
// Display the string
fmt.Printf("\nthe String is: %s", strng)
// Display the type of strng variable
fmt.Printf("\nType of strng is: %T", strng)
}
226 ◾ GoLang: The Ultimate Guide
Type Conversion
T(v) is a function that converts the value v to the type T. Here are some
numerical conversions:
var c int = 43
var d float64 = float64(i)
var e uint = uint(f)
c := 43
d := float64(i)
e := uint(f)
Type Assertion
We can use type assertion if you have a value and wish to convert it to
another or a specified type (in the case of an interface). A type assertion
takes a value and attempts to construct another version in the explicit type
supplied.
In the following example, the timeMap function accepts a value and, if
it can be represented as a map of interfaces{} keyed by strings, injects a new
entry named “updated at” with the current time value.
package main
import (
"fmt"
"time"
)
func main() {
foo := map[string]interface{}{
"Matt": 43,
}
timeMap(foo)
fmt.Println(foo)
}
package main
import "fmt"
func main() {
k := &fakeString{"Ceci n'est pas un string"}
printString(k)
printString("Hello, Everyone")
}
228 ◾ GoLang: The Ultimate Guide
if err != nil {
if msqlerr, ok := err.(*mysql.MySQLError); ok && msqlerr.
Number == 1062 {
log.Println("We got MySQL duplicate:(")
} else {
return err
}
}
Structs
A struct is a group of fields/properties. New types can be defined as structs
or interfaces. If we come from an object-oriented background, think of a
struct as a lightweight class that allows for composition but not inheritance.
We do not need to declare getters and setters on struct fields because
they are automatically accessible. However, only exported (capitalized)
fields may be accessed outside a package.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(Bootcamp{
Lat: 34.012837,
Lon: -118.495339,
Date: time.Now(),
})
}
GoLang for JavaScript Developers ◾ 229
By listing the values of its fields, a struct literal assigns a freshly allo-
cated struct value. Using the “Name:” syntax, we may list only a subset of
fields (the order of named fields is irrelevant when using this syntax). The
& prefix creates a reference to a newly allocated struct.
Structure literals are declared as follows:
package main
import "fmt"
var (
e = Point{1, 2} // has type Point
f = &Point{1, 2} // has type *Point
g = Point{X: 1} // D:0 is implicit
h = Point{} // X:0 and D:0
)
func main() {
fmt.Println(e, f, g, h)
}
package main
import (
"fmt"
"time"
)
func main() {
event := Bootcamp{
Lat: 34.012837,
Lon: -118.495339,
}
event.Date = time.Now()
230 ◾ GoLang: The Ultimate Guide
Initializing
The new expression in Go allows us to allocate a zeroed variable of the
specified type and return a pointer to it.
c := new(int)
package main
import (
"fmt"
)
func main() {
c := new(Bootcamp)
d := &Bootcamp{}
fmt.Println(*c == *d)
}
package main
import "fmt"
func main() {
p1 := Players{}
p1.Id = 28
p1.Name = "Katt"
p1.Location = "CA"
p1.GameId = 70414
fmt.Printf("%+v", p1)
}
package main
import "fmt"
func main() {
p1 := Players{}
p1.Id = 28
p1.Name = "Katt"
p1.Location = "CA"
p1.GameId = 70414
fmt.Printf("%+v", p1)
}
package main
import "fmt"
func main() {
p1 := Players{
GoLang for JavaScript Developers ◾ 233
We can’t merely pass the composed fields when using a struct literal with
an implicit composition. Instead, we must supply the types that make up
the struct. Once configured, the fields are immediately accessible.
Because our struct is made up of another struct, the User struct’s func-
tions are likewise accessible to the Player. Let us develop a way to demon-
strate that behavior:
package main
import "fmt"
func main() {
p1 := Players{}
p1.Id = 28
p1.Name = "Katt"
p1.Location = "CA"
fmt.Println(p1.Greetings())
}
234 ◾ GoLang: The Ultimate Guide
package main
import (
"log"
"os"
)
func main() {
job := &Job{"demo", log.New(os.Stderr, "Job: ", log.Ldate)}
// same as job := &Job{Command: "demo",
// Logger: log.New(os.Stderr, "Job: ", log.Ldate)}
job.Logger.Print("test")
}
Our Job struct contains a Logger field, which is a reference to another type
(log.Logger)
We set the logger when we create our value so that we may call its Print
function later by chaining the calls: a job.Logger.Print()
However, Go allows us to go much farther by employing implicit compo-
sition. We can forgo establishing the field for our logger because all methods
are now accessible via a reference to the log. Our struct has loggers available:
package main
import (
"log"
"os"
)
1 https://www.GoLangbootcamp.com/book/types#sec-initializing_values
GoLang for JavaScript Developers ◾ 235
func main() {
job := &Job{"demo", log.New(os.Stderr, "Job: ", log.Ldate)}
job.Print("starting-now..")
}
We must still set the logger, which is frequently an excellent reason to use a
constructor (custom constructors are used when we need to set a structure
before utilizing a value). What’s excellent about implicit composition is
that it allows us to simply and inexpensively make our structs implement
interfaces. Assume we have a function that accepts variables and imple-
ments an interface with the Print method by adding *log.Logger to our
struct (and properly initializing it), our struct is now implementing the
interface without the need for us to write any new methods.
mkdir go_modules
cd go_modules
Use the following command to set the current directory as the root of the
module, which will allow us to handle dependencies:
2 https://www.geeksforgeeks.org/how-to-create-modules-in-GoLang/
236 ◾ GoLang: The Ultimate Guide
import("fmt")
We can additionally create another Go file with the following code to test
the function as mentioned above:
package gfg_go
import (
"testing"
"fmt"
"strings"
)
test_string1 := "go_modules"
if test_string1 == test_string2 {
fmt.Printf("Successful!\n")
} else {
// this prints error message if
// strings don't match
test.Errorf("Error!\n")
}
We should observe that our test builds passed after executing the go test
command.
module go_modules
go 1.14
• go.mod defines the name of a module, its dependencies, and its mini-
mal versions.
• go.sum is a dependency lock file that is created automatically.
Starting Out
Module Initializing
To begin, we must start the module within your project:
Inside, a go.mod file with the name of our project directory as the module
and the version of Go we are using will be produced.
Setting Up Dependencies
After initializing the go.mod file, we may use the go get command to get
specified versions of modules. Example:
$ go get -u github.com/gin-gonic/gin
The package manager will check for and download the dependency’s most
recent tag. Download all child dependencies required if the -u parameter
is used. The go.sum file will be added to our project after a dependency
for the project has been downloaded. The contents of the go.mod file are
changed to indicate all of the dependencies that have been downloaded in
their latest versions.
There will be times when we are creating code in our Go project, and the
dependencies have not been downloaded by the go get command but are
mentioned as an import statement. To confirm this, run/build our project,
which will automatically check for and download suitable versions of the
dependencies depending on our code.
$ go build
We may also just download the missing dependencies and not run/build
our project:
$ go mod download
$ go mod tidy -v
The program will produce the result shown below, and any unneeded
dependencies in the go.mod and go.sum files are deleted.
$ go mod tidy –v
Description Command
Install the latest tag version go get github.com/gin-gonic/gin
Install specific tag version go get github.com/gin-gonic/gin@v1.6.2
Install a specific branch go get github.com/gin-gonic/gin@master
Install specific commit go get github.com/gin-gonic/gin@1bdf86b
We may also alter the go.mod file and then run go mod download.
ERROR HANDLING
Errors suggest that something is wrong with the software. Assume we are
attempting to open a file that does not exist in the file system. This is an
aberrant condition, and an error indicates it.
In Go, errors are just values. The built-in error type is used to express
errors. Later in this course, we’ll learn more about the error type.
Error-values are kept in variables, supplied as parameters to functions,
returned from functions, and so on, much like any other built-in type,
such as int, float64, etc.
Let’s begin with an example program that attempts to open a file that
does not exist.
package main
import (
"fmt"
"os"
)
GoLang for JavaScript Developers ◾ 241
func main() {
f, err := os.Open("/test.txt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(f.Name(), "open-successfully")
}
We attempt to open the file /test.txt (which will not exist in the play-
ground). The os package’s Open function has the below given signature:
If the file is opened successfully, the Open method will return the file han-
dler, and the error value will be nil. If an error occurs when opening the
file, a non-nil error is returned.
If a function or method delivers an error, it is often the final value
returned by the function. As a result, the Open function returns err as to
the final value.
In Go, the natural approach to handling errors compares the returned
error to nil. A nil value implies that no error happened, but a non-nil value
indicates that an error occurred. We check to see if the error is not nil in
this situation. If it is not nil, we simply print an error message and exit the
main function.
When we run this code, it will print:
It only has one method with the signature Error() string. As an error, any
type that implements this interface can be used. This function returns an
error explanation.
When printing the error, the fmt.Println function internally uses the
Error() string method to obtain the error information.
We can analyze this error message to obtain the file path “/test.txt” of the
file that produced the issue. However, this is a crude method. In subse-
quent versions of Go, the error description might change at any time, caus-
ing our code to fail.
But do you think there is a more efficient way to obtain the file
name? Yes, it is possible, and the Go standard library employs various
methods to convey additional information about mistakes. Let’s take a
look at them one at a time.
We can see from the code above that *PathError implements the
error interface by declaring the Error() string function. This func-
tion returns the operation, path, and actual error concatenation. As a
result, we received the error notice,
PathError struct’s Path field contains the file’s path that generated
the error. Let’s change the code we built before to print the path.
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("test.txt")
if err != nil {
if pErr, ok := err.(*os.PathError); ok {
fmt.Println("Failed to open file at path",
pErr.Path)
return
}
fmt.Println("Generic-error", err)
return
}
fmt.Println(f.Name(), "open-successfully")
}
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.LookupHost("GoLangbot123.com")
if err != nil {
if dnsErr, ok := err.(*net.DNSError); ok {
if dnsErr.Timeout() {
fmt.Println("operation timed-out")
return
}
3 https://GoLangbot.com/error-handling/
GoLang for JavaScript Developers ◾ 245
if dnsErr.Temporary() {
fmt.Println("temporary-error")
return
}
fmt.Println("Generic DNS-error", err)
return
}
fmt.Println("Generic-error", err)
return
}
fmt.Println(addr)
}
package main
import (
"fmt"
"path/filepath"
)
func main() {
files, err := filepath.Glob("[")
if err != nil {
if err == filepath.ErrBadPattern {
fmt.Println("Bad pattern-error:", err)
return
}
fmt.Println("Generic-error:", err)
return
}
fmt.Println("matched-files", files)
}
package main
import (
"fmt"
GoLang for JavaScript Developers ◾ 247
"path/filepath"
)
func main() {
files, _ := filepath.Glob("[")
fmt.Println("matched-files", files)
}
We already know that the pattern is incorrect from the prior case. In line 7,
we used the blank identifier to disregard the error provided by the Glob
function. In line 8, we just print the matched files. This program will print,
matched files []
Because we disregarded the error, the result shows that no files fit the pat-
tern, but the pattern itself is incorrect. As a result, never overlook mistakes.
First Example:
import "fmt"
// Main-function
func main() {
248 ◾ GoLang: The Ultimate Guide
Second Example:
import "fmt"
// Main-function
func main() {
GoLang for JavaScript Developers ◾ 249
// Creating, initializing
// slice of string using
// the shorthand declaration
myslice := []string{"Peeks", "Peeks",
"pfp", "PFP", "for"}
Syntax:
Example:
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Compare("PeeksforPeeks",
"PeeksforPeeks"))
fmt.Println(strings.Compare("PeeKS", "PeeKs"))
FUNCTIONS IN Go
Functions are frequently coding blocks or statements in a program that
allow the user to reuse the same code, saving memory and time, and, most
importantly, increasing code readability. A function is, in essence, a col-
lection of statements that together perform a particular task and provide
the result to the caller. A function can also complete a job without return-
ing any results.
Function Declaration
A function declaration is a technique for creating a function.
Syntax:
func function_name(Parameter-list)(Return-type){
// function-body
}
GoLang for JavaScript Developers ◾ 251
Function Calling
When a client needs to run a function, they invoke or call it. The function’s
capabilities must be provided to be used. As shown in the example below,
we have an area () function with two parameters. We refer to this function
by its name, area(23, 12), with two parameters in the main function.
// main-function
func main() {
// Display area of the rectangle with
// method calling
fmt.Printf("Area of rectangle is : %d",
area(23, 12))
}
Function Arguments
In Go, the arguments sent to a function are known as real parameters, but
the parameters received by a function are known as formal parameters.
The Go language utilizes the call by value mechanism by default to pass
parameters in a function. For providing parameters to our function, the
Go programming language gives two options:
• Call by value: The values of actual parameters are passed to the
function’s formal parameters in this method of parameter passing,
and the two types of parameters are retained in separate memory
regions. As a result, any modifications made within functions do not
appear in the caller’s actual parameters.
Example:
// Program to demonstrate the
// concept of call by value
package main
import "fmt"
// the function which swap values
func swap(c, d int)int{
var o int
o= c
c=d
d=o
return o
}
// main-function
func main() {
var x int = 27
var y int = 40
fmt.Printf("x = %d and y = %d", x, y)
// call by values
swap(x, y)
GoLang for JavaScript Developers ◾ 253
Example:
// Program to show the
// the concept of call by reference
package main
import "fmt"
// function which swap the values
func swap(c, d *int)int{
var o int
o = *d
*c = *d
*d = o
return o
}
// main-function
func main() {
var x int = 20
var y int = 10
fmt.Printf("x = %d and y = %d", x, y)
// call by reference
swap(&x, &y)
fmt.Printf("\n x = %d and y = %d", x, y)
}
Syntax:
func function_name(parameter_list)(returntype_list){
// code
}
254 ◾ GoLang: The Ultimate Guide
Example:
// program to show how a function may return
several values
package main
import "fmt"
// myfunc return three values of the int type
func myfunc(c, d int)(int, int, int ){
return c - d, c * d, c + d
}
// main-Method
func main() {
// return values are assigned into the
different variables
var myvar1, myvar2, myvar3 = myfunc(41, 22)
// Displayvalues
fmt.Printf("Result is: %d", myvar1 )
fmt.Printf("\nResult is: %d", myvar2)
fmt.Printf("\nResult is: %d", myvar3)
}
Syntax:
func function_name(para1, para2 int)(name1 int,
name2 int){
// code
}
Example:
// show how to give names to return the values
package main
import "fmt"
// myfunc return two values of int type
// here return the value name is rectangle & square
GoLang for JavaScript Developers ◾ 255
VARIADIC FUNCTIONS
A variadic function takes a variable set of variables to invoke. In other
words, the variadic function will accept zero or more arguments from the
user.fmt. Printf is an example of a variadic function; it takes one fixed
parameter at the beginning and can take any number of arguments
afterward.
Syntax:
function function_name(para1, para2...type)type{
// code..
}
Example:
// Program to show the
// concept of variadic function
package main
import(
"fmt"
"strings"
)
// Variadic function to join string
func joinstr(element...string)string{
return strings.Join(element, "-")
}
func main() {
256 ◾ GoLang: The Ultimate Guide
// zero-argument
fmt.Println(joinstr())
// multiple-arguments
fmt.Println(joinstr("Heyyy", "HEW"))
fmt.Println(joinstr("Heyyy", "Everybody",
"World"))
fmt.Println(joinstr("H", "E", "Y", "Y", "Y"))
}
ANONYMOUS FUNCTION
The Go scripting language has an anonymous function. An anonymous
function lacks a name. When it is necessary to write an inline function, an
anonymous function can create a closure in Go. Anonymous functions are
also known as function literals.
Syntax:
func(parameter_list)(return_type){
// code
// Use return-statement if returntype are given
// if return_type is not given, then do not
// use the return statement
return
}()
Example:
// Program to show how to create anonymous
function
package main
import "fmt"
func main() {
// anonymous-function
func(){
fmt.Println("Welcome to Home")
}()
}
main() Function
In Go, the main package is a one-of-a-kind package that contains exe-
cutable programs, such as the main() function. The main() function is
a one-of-a-kind function that acts as the executable program’s starting
point. It takes no parameters and returns none. There is no need to invoke
the main() method directly because Go executes it for you, and every
executable program must include a single main package and the main()
function.
Example:
// Program to illustrate the concept of main()
function
// Declaration of the main package
package main
// Importing-packages
import (
"fmt"
"sort"
"strings"
"time"
)
// Main-function
func main() {
// Sorting given slice
str := []int{455, 39, 223, 29, 86, 38, 427, 29}
sort.Ints(str)
fmt.Println("Sorted slice: ", str)
// Finding-index
fmt.Println("The Index value is: ", strings.
Index("Hello", "ks"))
// Finding-time
fmt.Println("Time is: ", time.Now().Unix())
}
init() Function
Like the main function, the init() function accepts no parameters and
returns nothing. This function is included in every package and is called
when the package is loaded for the first time. Because this function is
declared implicitly, we can’t use it anywhere else. In the same application,
we can build many init() functions and will execute them in the order
258 ◾ GoLang: The Ultimate Guide
in which they are built. Init() functions can be inserted anywhere in the
program and are called in the order of the lexical file name. And state-
ments are allowed if the init() function is used, but please remember that
the init() method is executed before the main() function call, so it is not
dependent on the main() function.
Example:
// Program to show the
// tconcept of init() function
// Declaration of the main package
package main
// importing-package
import "fmt"
// multiple init()-function
func init() {
fmt.Println("Welcome home")
}
func init() {
fmt.Println("Hello everybody ")
}
// main-function
func main() {
fmt.Println("Welcome to class")
}
Code Optimization
IN THIS CHAPTER
➢➢ Optimization tips
➢➢ Writing secure code
➢➢ Best coding practices
➢➢ Security and hardening ideas
import "github.com/gorilla/mux"
import "net/http/pprof"
var handler *mux.Router
// .....
handler.PathPrefix("/debug/pprof/profile")
.HandlerFunc(pprof.Profile)
handler.PathPrefix("/debug/pprof/heap")
.HandlerFunc(pprof.Heap)
Result:
Result:
What this does is output the source lines of the function we’re inter-
ested in and count which statements generated heap allocations
within the function. This is one of several commands available within
pprof. Another handy one is peeking, which displays the callers and
callees of functions. By entering “help” and playing with what we see,
we can receive a comprehensive list.1
Result:
Total: 11323262665
ROUTINE ======================== github.com/signalfuse/
sfxgo/ingest/bus/rawbus.(*Partitioner).Partition in /
opt/jenkins/workspace/ingest/gopath/src/github.com/
signalfuse/sfxgo/ingest/bus/rawbus/partitioner.go
927405893 927405893 (flat, cum) 8.19% of Total
. . 64: if ringSize == 0 {
. . 65: return 0, ErrUnsetRingSize
. . 66: }
. . 67: var b1 [8]byte
. . 68: binary.LittleEndian.
PutUint64(b1[:], uint64(message.Key.
(*partitionPickingKey).tsid))
239971917 239971917 69: logherd.Debug2(log, "key",
message.Key, "numP", numPartitions, "Partitioning")
. . 70: murmHash := murmur3.
Sum32(b1[:])
. . 71:
. . 72: // 34026 => 66
. . 73: setBits := uint(16)
. . 74: setSize := uint32
(1 << setBits)
. . 75: shortHash := murmHash &
(setSize - 1)
1 https://www.splunk.com/en_us/blog/devops/a-pattern-for-optimizing-go-2.html
Code Optimization ◾ 263
What this achieves is that the -m argument for a building will output
to stderr the compiler’s optimization decisions. This covers whether
the compiler may allocate a variable on the stack or if it must relocate
it to the heap. If the compiler cannot ensure that a reference to the
variable is not found elsewhere, Go will relocate it to the heap.
264 ◾ GoLang: The Ultimate Guide
Result:
What this implies is that the essential sections are on line 77, which
shows that smallIndex, murmHash, and shortHash all escape to the
heap. I’m producing more objects on the heap than we need since the
compiler executes short-lived heap allocations.
• Step 6: Benchmark the Partition Function
What we should write:
This runs benchmarks that match the regex “.” and -benchmem will
also run benchmarks that measure heap use on average each itera-
tion. By supplying _NONE_ to -run, we’re instructing tests to exe-
cute unit tests with the “_NONE_” string inside them, which saves
us some time. In other words, run all of the benchmarks but none of
the unit tests.
Result:
PASS
BenchmarkPartition-8 10000000 202 ns/op 64
B/op 4 allocs/op
Result:
Result:
PASS
BenchmarkPartition-8 30000000 40.5 ns/op
0 B/op 0 allocs/op
ok github.com/signalfuse/sfxgo/ingest/bus/rawbus
1.267s
This implies that each operation now takes only 40ns, and there are no
allocations per operation. This is the essential element for us because we
attempted to optimize heap consumption.
Improved Consistency
Consistency is like cleaning; no one sees it when it’s done well, but
when neglected, the entire home looks sloppy, and we find ourselves in
disarray.
Accomplishing perfect consistency is difficult since guaranteeing back-
ward compatibility can hinder progress, but paying attention to employ-
ing clear coding principles, compatible APIs, and consistent standards can
undoubtedly alleviate the suffering.
Maintaining code consistency in mind is especially crucial when deal-
ing with legacy code or more significant projects with multiple developers.
Enhanced Workflow
Many web development projects are managed by remote or distributed
teams, such as open-source communities. One of the most challenging
aspects of managing such a process is making communication effec-
tive enough for team members to understand each other readily and not
explain settings continuously.
270 ◾ GoLang: The Ultimate Guide
Best practices and style guidelines that are agreed upon may bridge the
gap between people from diverse backgrounds, not to mention the regular
communication challenges that most online projects have between design
and development teams.
Code optimization is also workflow optimization since if team mem-
bers speak the same language and have the same stated goals, they will be
able to work together much more quickly.
others, and you must identify these red flags in our application program. It
might be the CPU, the bandwidth, or the RAM.
Efficiency of Algorithms
A program can do the same task in various methods with variable mag-
nitudes. By using algorithm optimization, we will get maximum per-
formance in our application. Continue reading our article to meet and
overcome the three efficiencies mentioned above (latency, resource, and
algorithm) in our GoLang application. It is a hand-picked list compiled
with the assistance of our knowledgeable Go engineers.
When we hire a GoLang developer from us, we will receive all of the
experience required to create an application for our users.
Contrast Go currently offers just IAST sensors for assessing code dur-
ing the build and test processes. In keeping with the Contrast Application
Security Platform’s whole software development life cycle, future Contrast
Go features will include runtime application protection and observability
to safeguard Go apps in production.
while using Go.2 That’s precisely what we’re going to do this time. We’ll go
through practices to keep in mind when working using Go in this piece.
package main
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
)
func main() {
v1 := validator.New()
a1 := User{
Email: "a1",
}
err := v1.Struct(a1)
2 https://blog.sqreen.com/top-6-security-best-practices-for-go/
278 ◾ GoLang: The Ultimate Guide
package main
import (
"html/template"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
param1 := r.URL.Query().Get("param1")
tmpl := template.New("heyyy")
tmpl, _ = tmpl.Parse('{{define "T"}}{{.}}{{end}}')
tmpl.ExecuteTemplate(w, "T", param1)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
As discussed in the previous section, it’s also good to sanitize the user’s
input or escape special characters using the HTMLEscapeString method
from the HTML template package.
The most important piece of code we’d need to add, though, is the usage
of parameterized queries. On the go, we prepare a statement on the DB
rather than in a connection. Here’s an instance of how parameterized que-
ries are used:
customerName := r.URL.Query().Get("name")
db.Exec("UPDATE creditcards SET name=? WHERE customerId=?",
customerName, 123, 70)
But what if the database engine doesn’t support prepared statements? What
if it has an impact on query performance? We can use the db.Query()
method, but we must first sanitize the user’s input, as shown in earlier sec-
tions. Other third-party libraries are available to prevent SQL injections,
such as sqlmap.
Despite our best efforts, vulnerabilities occasionally sneak through or
reach our apps via third parties. Consider using an application security
management platform like Sqreen to defend our web apps against essential
threats like SQL injections.
package main
import (
"database/sql"
280 ◾ GoLang: The Ultimate Guide
"context"
"fmt"
"GoLang.org/x/crypto/bcrypt"
)
func main() {
ctx := context.Background()
email := []byte("rohan.doe@somedomain.com")
password := []byte("47;u5:B(95m72;Xq")
Here is some code for a web application that uses and enforces the
HTTPS protocol:
package main
import (
"crypto/tls"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req
*http.Request) {
w1.Header().Add("Strict-Transport-Security",
"max-age=53072000; includeSubDomains")
w1.Write([]byte("This is server example.\n"))
})
cfg := &tls.Config{
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.
CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
},
}
srv := &http.Server{
Addr: ":443",
Handler: mux,
TLSConfig: cfg,
TLSNextProto: make(map[string]func(*http.Server,
*tls.Conn, http.Handler), 0),
}
log.Fatal(srv.ListenAndServeTLS("tls.crt", "tls.key"))
}
It’s worth noting that the app will be listening on port 443. The line that
enforces the HTTPS setting is as follows:
w.Header().Add("Strict-Transport-Security", "max-age=53072000;
includeSubDomains")
282 ◾ GoLang: The Ultimate Guide
We may also wish to include the server name in the TLS settings, as
seen below:
Even if our web app is solely used for internal communication, implement-
ing in-transit encryption is always a smart idea. Consider the possibility
that an attacker may sniff your internal traffic for whatever reason. It’s
always smart to raise the challenge bar for potential future attacks wher-
ever feasible.
if err != nil {
// handle error
}
In addition, Go provides a native library for working with logs. The most
straightforward basic code is as follows:
package main
import (
"log"
)
Code Optimization ◾ 283
func main() {
log.Print("Logging in the Go")
}
package main
import (
"os"
log "github.com/sirupsen/logrus"
)
func main() {
file, err := os.OpenFile("info.log", os.O_CREATE|os.
O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
log.SetOutput(file)
log.SetFormatter(&log.JSONFormatter{})
log.SetLevel(log.WarnLevel)
log.WithFields(log.Fields{
"animal": "fish",
"size": 20,
}).Info("A group of fish emerges from the ocean")
}
Syntax
Go is a compiled static language. This means that there are some ground
rules that we must follow. This will help reduce confusion while working
in a large team when each group must build its code and verify it is com-
patible with the others.
func main(){
var c int = 2022
//do-something
}
case int:
//do some other-thing
default:
//yet another-thing
}
}
}
Go Code Organization
Let’s look at how a perfect Go program/package code is structured.
import (
"fmt"
"io/ioutil"
"net/http"
"os"
GoLang Tutorials
and Projects
IN THIS CHAPTER
go get github.com/boombuler/barcode
Development
Main.go Source Code
The main function starts with a call to http.HandleFunc instructs the http
package to use homeHandler to handle all requests to the web root (“/”).
homeHandler is a function of the type http.HandlerFunc. Its parameters
are an http.ResponseWriter and an http.Request.
ViewCodeHandler is a function that allows visitors to examine a cre-
ated QR-code on a new page. It will handle URLs that begin with “/genera-
tor/,” the template for the function. The contents of generator.html will be
read by ParseFiles and returned as a *template.
package main
import (
"image/png"
"net/http"
"text/template"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/generator/", viewCodeHandler)
http.ListenAndServe(":8080", nil)
}
t1, _ := template.ParseFiles("generator.html")
t1.Execute(w1, p1)
}
png.Encode(w, qrCode)
}
The FormValue function returns the value of the dataString input field,
which is used to produce the QR code with the Encode method.
<h1>{{.Title}}</h1>
<div>Enter string we want to QRCode.</div>
<form action="generator/" method=post>
<input type="text" name="dataString">
<input type="submit" value="Submit">
</form>
Implementation
Using the command line or putty, execute the run command “Go ahead
and run main.go”.
The client is the host (e.g., the browser) that sends a request to a web
server in the form of a URL for a particular service or data and receives
a response. The server is a distant computer that accepts and processes
requests before returning the necessary response data over the HTTP/
HTTPS protocol.
// go/src/http-client/main.go
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
c1 := http.Client{Timeout: time.Duration(2) * time
.Second}
resp, err := c1.Get("https://go.dev/")
if err != nil {
fmt.Printf("Error %s", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error %s", err)
return
}
....
resp, err := c1.Get("https://go.dev/")
if err != nil {
fmt.Printf("Error %s", err)
return
}
....
....
postData := bytes.NewBuffer([]byte('{"post":"boom-boom
library"}'))
resp, err := c1.Post("https://go.dev/", "application/json",
postData)
294 ◾ GoLang: The Ultimate Guide
if err != nil {
fmt.Printf("Error %s", err)
return
}
....
....
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error %s", err)
return
}
// go/src/http-client/main.go
package main
GoLang Tutorials and Projects ◾ 295
import (
"fmt"
"io/ioutil"
"net/http"
"time"
)
func main() {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error %s", err)
return
}
In the preceding code, we built a client and then specified a new request
using the http.NewRequest function. We described the type of request we
wanted using the parameters.
The function signature for http.Request is as follows:
The first argument specifies the request’s method. Then, in the second
argument, we supply the URL and the body to store the data or nil in the
case of a GET request because there is nobody to transmit.
296 ◾ GoLang: The Ultimate Guide
req.Header.Add("Accepted", 'application/json')
Header fields are used to add and convey additional information about the
request to the server. The HTTP 1/1 protocol includes numerous Header
fields:
....
req, err = http.NewRequest("GET", "https://www.xxxx.xxx", nil)
req.Header.Add("Accept", 'application/json')
GoLang Tutorials and Projects ◾ 297
package main
// important libraries
import (
"fmt"
"log"
"net/http"
)
// Home function
func Home()(w1 http.ResponseWriter, r1 *http.Request){
// This is what function will print.
fmt.Fprintf(w, "Welcome to Home!")
}
// function to handle the requests
func handleReq() {
// will call the Home function by default.
http.HandleFunc("/", Home)
log.Fatal(http.ListenAndServe(":8200", nil))
}
func main() {
// starting the API
handleReq()
}
Let’s expand on this by adding another endpoint. We’ll modify the code
above to include a new function, return_contact().
package main
// important-libraries
import (
"fmt"
"log"
"net/http"
)
// Home-function
func Home()(w http.ResponseWriter, r *http.Request){
// This is what the function will print.
fmt.Fprintf(w, "Welcome to Educative Home!")
}
func return_contact()(w http.ResponseWriter, r *http.
Request){
// This is what the function will print.
fmt.Fprintf(w, "Email: support@educative.io")
}
GoLang Tutorials and Projects ◾ 299
log.Fatal(http.ListenAndServe(":8200", nil))
}
func main() {
// starting API
handleReq()
}
A user may now reach the endpoint contact by typing and inputting the
URL:
http://localhost:8200/contact
Project Setup
mkdir GoLang-api
cd GoLang-api
go mod init github.com/cameronldroberts/GoLang-api
touch main.go
We’re finally ready to get started with the coding. Open the GoLang-api
project in our preferred editor and navigate to main.go, which contains
the code.
Imports
First, we’ll go over imports, which are how we bring in other Go modules.
A module in Go is a grouping of one or more packages that contain related
code. The following four will be used to access the API. Depending on the
editor (and settings) we use, imports may be handled automatically, and
we may not need to perform the next step of manually adding imports.
300 ◾ GoLang: The Ultimate Guide
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
Example of a Response
This is an example of a response from the API when we call it. We can
transfer the structure of the JSON answer that we will get into a struct
because we know its structure.
{
"id": "XgVnOK6USnb",
"jokes": "What did the calculator say to the student? We
can count on us",
"status": 200
}
Struct
Because the struct is quite simple, mapping from JSON to the struct below
would not be too complex in this case.
Code
Finally, a method invokes the API and processes the response. It is not
recommended to place function logic within main() while working with
Go because this is the entry point for our application. For the sake of this
essay, we will put the code in main, however this is not recommended
while programming in the real world.
GoLang Tutorials and Projects ◾ 301
func main() {
fmt.Println("Calling API....")
client := &http.Client{}
req, err := http.NewRequest("GET", " http://www.
laughfactory.com/jokes/clean-jokes", nil)
if err != nil {
fmt.Print(err.Error())
}
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Print(err.Error())
}
var responseObject Response
json.Unmarshal(bodyBytes, &responseObject)
fmt.Printf("API Response as a struct %+v\n",
responseObject)
}
go run main.go
The main will be compiled and run as a result of this. Go ahead and file. If
everything went correctly, we should have jokes written into our terminal.
The output should look like this:
302 ◾ GoLang: The Ultimate Guide
go run main.go
Calling API....
API Response as struct {ID:5h399pWLmyd Jokes:What did the
beaver say to the tree? It's been nice gnawing us.
Status:200}
Complete code:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Response struct {
ID string 'json:"id"'
Jokes string 'json:"jokes"'
Status int 'json:"status"'
}
func main() {
fmt.Println("Calling API....")
client := &http.Client{}
req, err := http.NewRequest("GET", " http://www
.laughfactory.com/jokes/clean-jokes", nil)
if err != nil {
fmt.Print(err.Error())
}
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
fmt.Print(err.Error())
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Print(err.Error())
}
var responseObject Response
json.Unmarshal(bodyBytes, &responseObject)
fmt.Printf("API Response as a struct %+v\n", responseObject)
}
Go IS FAST
Go is a speedy scripting language. It is compiled to machine code and will
automatically outperform interpreted or virtual runtime languages. Go
apps compile rapidly as well, and the final binary is small. Our API deliv-
ers an 11.5 MB executable file in seconds.
EASY TO UNDERSTAND
Go’s syntax is short compared to other languages, making it easy to learn.
We can recall most of it, so we don’t need to spend much time looking it
up. It’s also immaculate and easy to read. Non-Go programmers, espe-
cially those accustomed to C-style syntax, can usually read a Go program
and comprehend what’s going on.
STATIC TYPING
Go is a computer language that is strongly typed and statically typed.
Integer, byte, and string are examples of primitive types. Another sort of
structure is structure. Like any strongly typed language, the type system
allows the compiler to catch entire classes of issues. Go has simple-to-use
built-in types for lists and maps.
TYPES OF INTERFACES
In Go, interfaces exist, and any struct can implement an interface by sim-
ply implementing its methods. This helps you to decouple the dependen-
cies in our code. Dependencies can then mock in tests. Using interfaces,
we may create more modular, testable code. Go also has first-class func-
tions, which helps us write more functional code.
STANDARD LIBRARY
Go includes an excellent standard library. It has handy built-in functions for
working with primitive types. Packages make it easy to set up a web server,
manage I/O, interface with encryption, and process raw data. JSON seri-
alization and deserialization in the standard library are straightforward.
Using “tags,” we can add JSON field names directly next to struct fields.
GARBAGE COLLECTION
Memory management in Go was more straightforward than that in C and
C++. Objects that have been dynamically allocated are destroyed. Because
it does not support pointer arithmetic, Go makes using pointers safer. It
also supports the use of value types.
Appraisal ◾ 305
TESTING ASSISTANCE
Testing support is included in the standard library. There is no need for
reliance. If we have a code called example.go ahead and save our tests in
a file named thing test.go, and then run “go test” Go will perform these
tests rapidly.
GoLang’s Definition
Google’s GoLang programming language is an open-source project. It was
designed to be a better choice for creating big programs, particularly those
that require concurrency capabilities, such as channels and goroutines.
GoLang can also compile code into the machine’s native instruction set,
allowing it to execute quicker than other languages.
GoLang’s FUTURE
GoLang’s future appears promising. The language will continue to be
developed as developer demands evolve, and it will very certainly become
more popular in the future years. As a result, if we don’t want to fall
behind, we should plan on learning it, as GoLang is superior to other pro-
gramming languages.
CREATING A WEBSITE
It’s time to reconsider your attitude about GoLang. Investigate the fac-
tors contributing to GoLang’s remarkable rise in popularity in recent
years. Other computer languages, such as Python and Ruby, perform
worse than GoLang. Because it can be compiled into native code,
GoLang outperforms other programming languages. Google’s Native
Client toolchain, on the other hand, has no dependencies for standalone
apps (NAC).
NAC’s capability allows enterprises to search for lightning-fast out-
comes from their programs. As a result, there is no bloat or extra baggage
that is sometimes associated with other programming languages.
Because it does not require a runtime, Google’s GoLang is faster than
any other language. As a result, execution is substantially quicker than in
Java or C++, and even faster in memory-constrained systems like embed-
ded devices.
Encapsulation
One of the nicest aspects of Go is that capitalized fields, methods, and
functions are all public. All other fields are unique to the package and
are not exported. We can tell if anything is public or private with a single
glance. There are no safeguards since there is no legacy.
Appraisal ◾ 315
Interfaces
Forget about Java and PHP-style interfaces. Interfaces in Go are consider-
ably different, and one important aspect is that interfaces are met implicitly.
Interfaces are often relatively tiny, consisting of only one method. In
idiomatic Go, we won’t find extensive lists of methods.
Interfaces neatly provide polymorphism: by adopting an interface, we
announce our readiness to embrace any kind of object that satisfies that
interface.
Methods
Methods exist for types. They are specified outside of the type defini-
tion, using a syntax that may be familiar to JavaScript prototype method
declarations.
Functions
Consider a standard object-oriented programming language, such as Java.
How many times have we defined a class with static methods called “Utils”?
This is done to get around the idea that everything is an object and that
function definition must contain within classes. This does not happen in
Go since it contains functions. Not everything has to be an object or a
method in the real world. Although “classes” and “objects” are beneficial,
they cannot used for everything.
In Go, not everything is an object (and technically nothing is an object,
although some people refer to type values and variables as “objects”),
methods are functions connected with a type, but Go also permits func-
tions to reside outside of an object, similar to C functions.
316 ◾ Appraisal
Less Bloat
Overall, the Go object-oriented programming approach is highly versatile
and clear. Leaving classes and inheritance behind, we’ll notice very little
boilerplate, and instead of arguing over the ideal hierarchical structure for
classes, which becomes difficult to modify, we’ll have the ability to com-
pose and decompose types as needed.
web server because it was designed by Google to satisfy their internal web
infrastructure requirements. The actual benefit of using this technique is
that the app and server share the same codebase, resulting in improved
integration, scalability, and speed.
Distributed Services
Concurrency is required for services dispersed across a network, such as
those found in a microservices architecture. Because of Go’s advantages in
this area are well-suited for developing solutions that adhere to a distrib-
uted services model.
Using goroutines, software developers may provide the scalability
required to manage several threads simultaneously. In addition to Go chan-
nels, this functionality creates the concurrency required for distributed net-
work services. These Go code artifacts offer the communication object that
allows goroutines to communicate information. In addition to maintain-
ing the contact between goroutines, these objects offer the synchronization
required for scalable event processing across dispersed network systems.
Cloud-Native Development
Because of its concurrency and networking features, Go has emerged as the
language of cloud infrastructure. When we consider that Google built Go
318 ◾ Appraisal
specifically for this reason, its features correspond nicely with the needs of
cloud-native apps. Go’s creators designed it for portability in addition to its
built-in concurrency and networking features. These three characteristics
make it a viable solution for developing cloud-based apps.
The mobility of GoLang is due to its cross-platform compatibility.
We just need to write the code once using Go, and we can then deploy
it wherever. Because we only need to handle one codebase, this feature
makes maintainability significantly more realistic. If the software has to
be changed, we simply need to make one modification and then build it
for the appropriate deployment platform, whether Windows, Linux, or
macOS. It also supports x86, ARM, and other specialized technologies
like ppc64 and MIPS, so we may use it on services that use diverse CPU
architectures.
Machine Learning
Go’s adaptability as a general-purpose, cross-platform programming lan-
guage allows software developers to utilize its machine learning capabili-
ties. As a statically typed programming language, its binaries offer the
speed and performance required for CPU-intensive, high computation
computations. Its scalability, parallelism, and portability also provide data
scientists with the flexibility to construct large-scale machine learning
systems.
There are various machine learning libraries created in Go, in addition
to its built-in functionality. Platforms, such as GoLearn, Gorgonia, and
goml, are just a few examples. Using these technologies, software devel-
opers may integrate their code without relying on other libraries devel-
oped in a different programming language. Furthermore, because solution
architects only need to handle a single Go codebase, this integration pro-
vides excellent portability and maintainability.
HEYYY EVERYONE
heyyy.go
package main
import "fmt"
func main() {
message := greetMe("everyone")
fmt.Println(message)
}
Run:
$ go build
VARIABLES
Variable declaration:
CONSTANTS
const Phi = 1.818
Constants can take the form of a character, string, boolean, or numeric value.
Basic Types
Strings
str := "Heyyy"
str := 'Multiline
string'
Numbers
Typical types:
num := 4 // int
num := 4. // float64
num := 4 + 5i // complex128
num := byte('a') // byte (alias for uint8)
Other types
var u uint = 9 // uint (unsigned)
var p float32 = 32.7 // 32-bit float
Arrays
// var-numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}
Slices
slice := []int{12, 32, 47}
slice := []byte("Heyyy")
Pointers
func main () {
x := *getPointer()
fmt.Println("Value is", x)
}
Cheat Sheet ◾ 321
y:= new(int)
*y = 234
Type Conversions
x := 2
y := float64(x)
z := uint(x)
FLOW CONTROL
Conditional
if day == "saturday" || day == "sunday" {
rest()
} else if day == "tuesday" && isTired() {
groan()
} else {
work()
}
Statements in if
if _, err := doThing(); err != nil {
fmt.Println("Uh-oh")
}
Switch
switch day {
case "saturday":
// cases do not "fall through" by default!
fallthrough
322 ◾ Cheat Sheet
case "sunday":
rest()
default:
work()
}
For Loop
for count := 0; count <= 20; count++ {
fmt.Println("Counter is at", count)
}
For-Range Loop
entry := []string{"Jacky","Rohan","Lonas"}
for x, val := range entry {
fmt.Printf("At position %d, character %s is
present\n", x, val)
}
While Loop
k := 0
a := 42
for k != a {
k := guess()
}
FUNCTIONS
Lambdas
myfunc := func() bool {
return a > 20000
}
PACKAGES
Importing
import "fmt"
import "math/rand"
import (
"fmt" // give fmt.Println
"math/rand" // give rand.Intn
)
Aliases
import x "math/rand"
x.Intn()
Exporting Names
func Heyyy () {
···
}
Packages
package heyyy
CONCURRENCY
Goroutines
func main() {
// A "channel"
ch := make(chan string)
go push("Harry", ch)
go push("Kurly", ch)
Buffered Channels
ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// fatal error:
// all goroutines are asleep - deadlock!
Closing Channels
Closes a channel
ch <- 1
ch <- 2
ch <- 3
close(ch)
Closed if ok == false
k, ok := <- ch
Cheat Sheet ◾ 325
WaitGroup
import "sync"
func main() {
var wg sync.WaitGroup
ERROR CONTROL
Defer
func main() {
defer fmt.Println("Done")
fmt.Println("Working")
}
Deferring Functions
func main() {
defer func() {
fmt.Println("Done")
}()
fmt.Println("Working")
}
326 ◾ Cheat Sheet
func main() {
var x = int64(0)
defer func(x *int64) {
fmt.Printf("& %v Unix Sec\n", *x)
}(&x)
fmt.Print("Done ")
x = time.Now().Unix()
}
Unless we provide a reference to acquire the final value at the end of main,
the defer func utilizes the current value of x.
STRUCTS
Defining
type Vertex struct {
A int
B int
}
func main() {
v := Vertex{1, 2}
v.A = 4
fmt.Println(v.A, v.B)
}
Literals
v := Vertex{A: 1, B: 2}
// Field names can omitt
v := Vertex{1, 2}
// B is implicit
v := Vertex{A: 1}
Pointers to Structs
v := &Vertex{1, 2}
v.A = 2
METHODS
Receivers
type Vertex struct {
A, B float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.A * v.A + v.B * v.B)
}
v := Vertex{1, 2}
v.Abs()
Mutation
func (v *Vertex) Scale(f float64) {
v.A = v.A * f
v.B = v.B * f
}
v := Vertex{6, 13}
v.Scale(0.5)
// 'v' is updated
Interfaces
Basic interface:
Struct
Methods
func (k Rectangle) Area() float64 {
return k.Length * k.Width
}
328 ◾ Cheat Sheet
Interface Example
func main() {
var k Shape = Rectangle{Length: 3, Width: 4}
fmt.Printf("Type of k: %T, Area: %v, Perimeter:
%v.", k, k.Area(), k.Perimeter())
}
Bibliography
329
330 ◾ Bibliography
A B
AddInt64() method, 210 Backticks(“),using, 83–84
Advantages of GoLang, 307, BDD, see Behavior Driven Development
311–312 Behavior Driven Development (BDD), 181
Age() function, 177–178 Benefits of using GoLang, 307
Amazon and GoLang, 310 Bitwise operators, 53–54
Anonymous function, 256 Blank Identifier, 76, 96
App development, GoLang for, Boolean constant, 42–43
312–313 Boolean data type, 30, 224–225
Application, of GoLang, 309 Break statement, 220, 285
Arithmetic operators, 49, 50–51 Buffered channels, 324
Arrays, 65, 72–73, 320 Buffered I/O, making use of, 273
copying an array into another array, bufio.NewReader(os.Stdin), 21
68–69 Built-in testing and profiling framework, 7
creating and using an array, 65 Business, GoLang for, 311
shorthand declaration, using,
66–67
C
var keyword, using, 65–66
multidimensional array, 67–68 Capability of GoLang, 316
passing an array to a function, cloud-native development, 317–318
69–70 creating solutions using Go, 316
Assignment operators, distributed services, 317
54–56 machine learning, 318
Awesome Go, 172 server, development on, 317
color package, 174–175 versatility of GoLang, 318
Docker, 184 web, applications for, 316–317
Etcd, 181–182 Cgo program, 17
gen tool, 176–178 reducing/eliminating the use of, 272
Ginkgo, 181 Closing channels, 324
glide package, 180–181 Closures, 100
GoLang-set, 172–174 Cloud-native development, 317–318
goose package, 180 Code optimization, 259
Gorm, 178–180 CI/CD workflows, 286
Kubernetes, 184 ensuring immutability
now package, 175–176 and availability using
NSQ, 182–183 GOPROXY, 287
333
334 ◾ Index
H Interpretation, 311
Intrinsic capabilities of GoLang, 316
handleReq() method, 297
Ints, 78
Hardware, Go empowering, 6–7
IntsAreSorted, 78–79
Home() function, 297
ioutil.ReadFile(), 20
homeHandler, 290
ioutil.WriteFile(), 21
HTML templates, making use of, 278
IsNotExist() function, 18
HTTP Authorization request header,
296–297
HTTP client, 291–293 J
POST and GET requests, 293–294
JavaScript developers, GoLang for, 213
request headers, adding, 294–296
anonymous function, 256
error handling, 240
error type representation, 241–242
I
getting more information from an
Identifiers, 26 error, 242–246
If..else..if ladder, 61–63 ignoring errors, 246–247
If statement, 57–58, 321 functions in Go, 250
If…else statement, 58–60 function arguments, 252–253
Import declaration, 167–168 function calling, 251–252
Importing packages, 165 function declaration, 250–251
Import path, 167 Go modules, package management
Inheritance, 121–123 using, 237
composition vs., 230–235 dependency version, updating, 240
Init() function, 166–167, 257–258 initializing, 239
Input entries, verifying, 277 setting up dependencies, 239
inputReader.ReadString(‘n’), 21 unnecessary dependencies,
Installation of Go eliminating, 239–240
on Mac, 14 init() function, 257–258
first program, making, 16 loop control statements, 219
Go programs’ interaction with break statement, 220
programs written in C/C++, 17 continue statement, 221
implementing Go program, 16–17 Goto statement, 220–221
on Windows, 8 main() function, 257
determining preinstalled version, 9 modules making in GoLang, 235
downloading and installing Go, dependencies addition to Go
9–10 module, 237
Instrument-based security work, multiple values, function returning,
275–276 253
Integer constant, 40 return values, giving name to,
Integers, 28–29, 222–223 254–255
Interfaces, 118, 327 strings, techniques to compare, 247
implementing, 119–120 Compare() method, using, 249–250
making, 119 comparison operators, making use
polymorphism using, 123–124 of, 247–249
redundant functions, 120–121 types, 222
types of, 304 booleans, 224–225
338 ◾ Index
beginning, 153–154 W
same package, testing within, 156–157
Wages, 306
setup and teardown, 155–156
WaitGroup, 325
unique to Go, 154–155
Walmart Labs, 311
Unsigned integers, 28–29
Web, applications of GoLang for,
Untyped and typed numeric constants, 39
316–317
boolean constant, 42–43
Web application to generate QR code in
complex constant, 40–41
GoLang, 289
floating type constant, 41
development, 290
integer constant, 40
Generator.html source code, 291
string literals, 41–42
Main.go source code, 290–291
implementation, 291
V necessary package, installing, 290
Website, creating, 313
Variables in Go, 31, 43, 319
While loop, 322
declaring a variable, 32
Whitespace, 27
short variable declaration, using,
Windows, installing Go on, 8
35–38
determining preinstalled version, 9
var keyword, employing, 32–35
downloading and installing
global variables, 44–46
Go, 9–10
local variables, 43–44
Workspace, 163–164
Variadic functions, 255–256
Var keyword, 32–35, 65–66
Versatility of GoLang, 318 Y
Vibrant community, 305
Yahoo and GoLang, 309
ViewCodeHandler, 290–291