Web application using golang. Done as part of this course
https://app.pluralsight.com/library/courses/creating-web-applications-go-update/table-of-contents
Taken from the course To install local assets:
- install NodeJs (https://nodejs.org)
- install
grunt-cli
globally vianpm install -g grunt-cli
- run
npm install
from the root directory of the project - run
grunt
from the root directory of the project to compile CSS
To run the application:
- install the app with
go install <name-of-your-webapp>
- run with
bin/webapp
- navigate to
http://localhost:8000/html/home.html
- Go addresses challenges which is not addressed in any of the existing languages
- Fully Compiled - Similar to C++
- Simple - Python (No clutter, only 25 keyword)
- Concurrency - Used by Erlang which handles 1,00,000 of sequential processes effortlessly (scaling is better)
- Statically typed language - variables need not be defined before they are used.
play.golang.go
golang.org
- Tour of Go in the golang website - TODO: Add link
- effective go, TODO: Add link
- Packages -
golang.org/pkg/
- The Project -
golang.org/project/
(what all has changed as language has evolved) - Blog -
blog.golang.org
(Best Prctices are available here) - gocode -
github.com/nsf/gocode
(Code complete package)
- "package main" - Entry point of the go program
- "func main()" - First function which runs when program is executed
- functions are first class citizens in go
package main
func main() {
println("Hello Go!!")
}
go run src/main.go
orgo install src/example
- run the exe file which is generated in the bin folder
const (
message = "Hello Go!!"
)
- const variables cant be changed
var (
message string = "Hello Go!!"
newMessage string // if not assigned returns empty sting. Go assigns zero value to the variables if not assinged
)
- Runs for the first time whenever a module references another module
- init function is called after variable initialization but before any other function is called
- Tells go that this module needs to use funtions which are present in another module
- There are two ways to use import
import "fmt"
or
import (
"fmt"
)
- if we are importing a package and not using it we will be compilation error
var myInt int // simplify the parsing of the source code
myInt = 5
var myFloat float32 = 42. // directly assigning during declaration
str := "Hello Go!!" // short variable declaration
complexNum := complex(2, 3) // first class support for complex numbers, First argument is real and second one is imaginary.
// To fetch the real part use real(complexNum)
// To fetch the imaginary part use imag(complexNum)
const (
first = "first value"
)
const (
first = iota // assign 0 to first, 1 to second and 2 to third
second
third
)
const (
first = 1 << (10 * iota) // 2^0
second // 2^10
third // 2^100
)
myArray := [3]int{}
myArray[0] = 42
myArray[1] = 27
myArray[2] = ll
fmt.Println(myArray)
// Another way
myArray := [...]int{42, 27, 99}
// to print the size of the array
sizeOFArray := len(myArray)
- More flexible than array
mySlice := myArray[:] // [1:], [:3]
mySlice = append(mySlice, 100)
mySlice := []float32{14., 15., 16.}
// if more data gets added, slice has to copy the contents every time new data is added which is inefficient
fmt.Println(len(mySlice))
// make takes 2 or three arguments
// If two arguments then the second argument is the size of the slice and array both
// If three arguments, second argument = size of the slice, third arguemnt = size of the array
mySlice := make([]float32, 100)
- Customizable keys
- both key and value can be arbitrary data types
myMap := make(map[int]string) // int is the type of the key, string is type of the value
myMap[42] = "Foo"
myMap[12] = "Bar"
fmt.Println(myMap)
fmt.Println(myMap[42])
- Addition Operators or string concatenation operator
- subtraction operator
- remainder operator
- increment operator
- decrement operator
- Augmented assignment operator
add := 1 + 2
str := "Foo" + "Bar"
sub := 3 - 1
remainder := 12 % 4
div : 12 / 4
inc := 1
inc++
dec := 5
dec-- // these are considered as statements and cannot be added with other operators
dec += 5 // augmented operations
if foo == 1 {
println("bar")
} else {
println("lala")
}
// moving the initialization of foo inside if statement
if foo := 1; foo == 1 {
println("foo is 1")
}
switch foo := 1; foo {
case 1:
println("one")
case 2:
println("two")
}
switch {
case foo == 1:
println("one")
case foo > 2:
println("5")
}
for i:=0; i < 5; i++ {
println(i)
}
// while kind of for loop
for {
i++
println(i)
if i > 5 {
break
}
}
// looping over collection
s := []string{"foo", "bar", "buz"}
for idx, v := range s {
println(idx, v)
}
myMap := make(map[int]string) // int is the type of the key, string is type of the value
myMap[42] = "Foo"
myMap[12] = "Bar"
for k, v := range m {
println(k, v)
}
var option string
fmt.Scanln(&option) // sends the memory address to populate the value
- Pass by Value
- Pass by reference
- Variadic function
// defining a function
func sayHello() {
println("Hello")
}
// calling a function
func main() {
sayHello()
}
// function with parameters, pass by value
func sayHello(message string) {
println(message)
}
// func with parameters, pass by reference
func sayHello(message *string) {
println(*message) // dereferencing of pointer
*message = "bye"
}
// variadic functions
func sayHello (messages ...string) {
for _, message := range messages {
println(message)
}
}
- Single return value
- Multiple return value
- Named return parameters
func add(terms ...int) int {
result := 0
for _, term := range terms {
result += term
}
return result
}
func add(terms ...int) (int, int) {
result := 0
for _, term := range terms {
result += term
}
return len(terms), result
}
// calling function with multiple return values
numTerms, sum := add(1, 2, 3, 4)
func add(terms ...int) (numTerms int, sum int) {
sum := 0
for _, term := range terms {
sum += term
}
numTerms = len(terms)
return
}
// calling function with multiple return values
numTerms, sum := add(1, 2, 3, 4)
- Functions are first class citizen
func main() {
addFunc := func(terms ...int) (numTerms int, sum int) {
sum := 0
for _, term := range terms {
sum += term
}
numTerms = len(terms)
return
}
numTerms, sum := addFunc(1, 3)
}
type myStruct struct {
myField string
}
// instantiating a struct variable
foo := myStruct {}
foo.myField = "bar"
foo := mystruct{"bar"}
// to create objects on heap
foo := new(myStruct)
foo.myField = "bar"
type myStruct struct {
myMap map[string]string
}
func newMyStruct() *myStruct {
result := myStruct{}
result.myMap = map[string]string{} // this is instantiating the map
return &result
}
// instantiation
foo := newMyStruct()
foo.myMap["bar"] = "baz"
- Data is totally separated from the methods
- We can declare the methods anywhere in the package
func main() {
mp := messagePrinter{"Foo"}
mp.printMessage()
}
type messagePrinter struct {
message string
}
func (mp *messagePrinter) printMessage() {
println(mp.message)
}
- instead of inheritance we have composition
func main() {
emp := enhancedMessagePrinter{}
emp.message = "foo"
emp.printMessage()
// or
emp := enhancedMessagePrinter{messagePrinter{"Foo"}}
}
type messagePrinter struct {
message string
}
func (mp *messagePrinter) printMessage() {
println(mp.message)
}
type enhancedMessagePrinter struct {
messagePrinter // Anonymous field of messagePrinter type
}
- goroutines - go's thread like construct to run code/functions concurrently
- channels - sharing data between threads
- concurrency is not parallelism
- Concurrency - only one thing is being run at a time
- Parallelism - Multiple tasks run at same time
- Parallel programming can be done by adding
runtime.GOMAXPROCS(8)
in the code
func main() {
abcGen() // prints abc in order
go abcGen() // if only this is written, nothing will be printer as main has terminated
// so we must apply sleep for sometime to see the output
time.Sleep(100 * time.Millisecond)
}
func abcGen() {
for l := byte('a'); l < byte('z'); l++ {
go println(string(l))
}
}
- Allows messages to be passed in go routines .
- Ensures data is safely transferred
func main() {
runtime.GOMAXPROCS(8)
ch := make(chan string)
doneCh := make(chan bool)
go abcGen(ch)
go printer(ch, doneCh)
<-doneCh
}
func abcGen(ch chan string) {
for l := byte('a'); l < byte('z'); l++ {
ch <- string(l)
}
close(ch)
}
func printer(ch chan string, doneCh chan bool) {
for l := range ch {
println(<-ch)
}
doneCh <- true
}