Learning golang 01 - Basics
Learning go from the go tour
Intro
- Every go program is made of packages and “main” package is run first.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
In the above program math/rand has a file with the first statement package rand
Import statements
these are called factored imports
import (
"fmt"
"math/rand"
)
imports can be done this way as well
import "fmt"
import "math/rand"
Functions
functions can take zero or more variables. The type comes after the variable names
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
If similar stuff are together they can be clubbed together like so,
a, b int
functions can return any number of results
Named return value:
Function values can be named for example
package main
import "fmt"
func split(sum int) (x,y int) { // note the return declaration
x = sum * 4 / 9;
y = sum - x;
return
//only an empty return statement is enough
}
Variables with initializers
A var declaration can derive type from the initializer value
package main
import "fmt"
func main() {
var x = 10;
fmt.Println("%T: %v \n",x,x);
}
Short variable declaration using :=
Inside a function := is available to implicitly type derive from initialisor.
Outside a function all declaration has to use the suffix (var, func and so on) so the short variable declarator is not available.
Basic types
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
Zero values:
Variables declared without an explicit initial value are given their zero value
0 for numeric types,
false for the boolean type, and
"" (the empty string) for strings.
type conversion
The expression T(v) is used to type cast between compatible types.
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
or
i := 42
f := float64(i)
u := uint(f)
//Note that these are only possible inside functions and not outside
Type inference
When the right element was type unspecified and the left element is type specified, then it is easily derived
var i int
j := i
But in case of values it depends on the type of value
i := 42 //int
j := 3.142 //float
k := 0.867 + 0.5i //complex
Constants
Constants are similar to var, but cannot be changed later on constants cannot be declared using := assignment
Flow control statements
For loop
There is only for loop in golang. It has 3 components seperated by semicolons
- The init statement executed in the first iteration
- The condition expression that gets evaluated before every iteration
- The post statement: executed at the end of the statement
Unlike C and C++ it doesn’t require parenthesis. but the curly braces is necessary.
package main
import "fmt"
func main() {
sum := 0
for i:=0; i<100; i++ {
sum+=i
}
fmt.Println(sum)
}
The init and post statements are optional
package main
import "fmt"
func main() {
sum := 0
i:=0
for ; i<100 ; { //Notice that there are no init or post statements
sum+=i
}
}
You can drop the semicolons as well
package main
import "fmt"
func main() {
sum := 0
i := 0
for i<100 { //note no semicolon unlike previous
sum+=i
}
}
if the init condition is omitted, then it loops forever. There is no while in golang
package main
import "fmt"
func main() {
for {
//this repeates forever
}
}
if statement
similar to for, if statements don’t require parentheses () but they need braces {}
package main
import(
"fmt"
"math"
)
func sqrt(x float64) string{
if x<0 {
return sqrt(-x)+"i"
}
return fmt.Sprint(math.sqrt(x))
}
func main() {
fmt.Println(sqrt(2), sqrt(-4))
}
// prints: 1.4142135623730951 2i
If with a short statement
If can have initialising statement. the variable is only available within the scope of the if.
package main
import (
"fmt"
"math"
)
func main(){
if v:=1;v<10 { //note the initialising statement
fmt.Println(v);
}
}
if and else blocks
Any variable initialised at the if block is also available at the else block
Switch statements
Switch statement is a simpler way of writing if else functions. Go’s switch statements have the same syntax as if, they can have an initialising statement which makes them available everywhere.
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.\n", os)
}
}
Switch evaluation order
- top to bottom,
- stops executing whenever the right sequence is seen
Switch with no condition.
- Switch without any condition, makes the case as true by default. This makes it an easier way to write if conditions
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
switch {
case t.Hour() < 12 :
fmt.Println("Good Morning!")
case t.Hour() < 17 :
fmt.Println("Good Afternoon")
default:
fmt.Println("Good evening")
}
}
Defer statements
Defer statements execute after everything around it has been executed and returned
Defer functions are pushed into a call stack and executed in last-in-first-out order
Defer statement’s arguments are evaluated immediately. But are executed at the end
package main
import "fmt"
func main() {
defer fmt.Println("World") // This will be printed in the end
fmt.Println("Hello")
}
//This would print: Hello World
Pointer
Pointers are references to the memory ho
var p *int
The & operator generates a pointer to its operand
i := 42 //implicit type int
var k *int = &i
The * operator denotes the value behind the pointer
fmt.Println(*p) // read i through the pointer p
*p = 21 // set i through the pointer p
Struct
A struct is a collection of fields.
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1,2})
}
Struct Literals
Structs can be defined by {Name: value}
syntax.
package main
import "fmt"
type Vertex struct{
X,Y int
}
func main() {
v = Vertex{X:1, Y:2} //The order doesn't matter
}
Struct fields are accessed using a dot
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
k := Vertex{2,3}
fmt.Println(k.X)
fmt.Println(k.Y)
}
Pointers to Struct
Struct fields can be accessed through pointers. But it is cumbersome to write *<pointer_name> every time. So the * can be ignored without explicit dereference.
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main () {
v:=Vertex{1,2}
v.X = 23
fmt.Println(v) //prints { 23 2 }
}