Basics
Basic Infoπ
- Go programs are made up of packages
- Execution of program starts from
main()
function inmain
package. - Example
math/rand
comprises of files that starts withpackage rand
-
use parenthesized import statement for multiple imports
-
Exporting β Everything which starts from capital letter is exportable in go. all remaining are accessible at package level .
How to executeπ
- Execution of program starts from
main()
function in main package - There should be only one
main.go
file in single project. - To run use command
go run main.go
- To build use command
go build .
note: in order to use build command you should initialize go-modules for project directory
Variablesπ
- you can declare variables like
var name string
orvar name = "qwerty"
orname := "qwerty"
. - you can also declare multiple variables on same line using wallrus(:=) operator
a,b := 1,2
- There are local and global variables local are bound the scope of block or function. global variables are accessible through out the package.
Warning
global variables cannot be declared by wallrus operator
Data Typesπ
- everything in go is type just like everything in python is object.
- go provide basic types such as integer, float, boolean, string, byte, rune, complex
integer
is further devided into int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.int
anduint
are atleast 32 bit in nature but not alias for int32 or uint32 it can also be 64 bit depending upon operatinf system.
floats
can be declare as float32(4 bytes), float64(8 bytes) default float type inferred is float64.complex
number are 2 types complex64 and complex128 default is complex128.byte
is alias for uint8.rune
is alias for int32. integer value is meant to represent unicode code point. unicode code reprents character like U+0030 but it doesn't know how to save it. this is where utf-8 comes in picture utf-8 saves character using 1,2,3,4 bytes ascii representation are saved using 1 byte. that's why rune is int32 so maximum storage length of utf-8 is 4 bytes and every string in go is encoded using utf-8. you can read more about unicode in this blog https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/string
is slice of bytes and can be declare using double qoutes which respects escape sequence while raw string does not.boolean
βOR ||
AND &&
NEGATION !
Control flowπ
- Go provide control flow statement such as if - else, switch, for loop.
-
Brackets in Go if else around the condition are omitted.
-
short statement can also be used such as assigning and putting condition on it.
-
switch statement
-
for loop β init and post part are optional remove them and you will get while loop. remove all and get while loop infinity. use
continue
andbreak
keyword to continue and break flow of loop respectively. use range keyword to get iterator dynamicallypackage main import "fmt" // loops in golang // golang only provide for loop func loop() { count := 5 // normal loop for i := 0; i < count; i++ { fmt.Println(i) } // while loop i := 0 for i < count { fmt.Println(i) i++ } // infinte while loop count = 0 for { if count > 4 { break } fmt.Println(count) count++ } // range loop names := []string{"alexa", "google homes", "siri", "cortana"} for idx, val := range names { fmt.Printf("index - %v value - %v\n", idx, val) } }
Functionsπ
-
basic function in golang
-
function with paramters
-
function with varidaic parameters
-
closure or inline function in go. It can also be assigned to variable
-
function with return type and return name and type declared
-
init
function - executes before main function and use cases include initilizing some value or configuration at runtime
- each package have there own init function
Errorsπ
- Goβs way of dealing with an error is to explicitly return the error as a separate value
-
you can check if returned error value from function is nil or not for error checking
-
custom error can be defiened using
errors.New("error something occurred")
- custom error with formatted message
fmt.Errorf("Err is: %s", "database connection issue")
- advanced custom error messages
- in below program
inputError
is a type of struct which implements theError()
interface method. - and
missingField
is addtional field ininputError
to provide more information about error along with itβs method calledgetMissingField
. - lastly
validate()
function will returnpointer to inputError that can be nil
andadvancedCustomError()
will type assert error and get the missing field name.// advanced custom error message func advancedCustomError() { err := validate("", "") if err != nil { if err, ok := err.(*inputError); ok { fmt.Println(err) fmt.Printf("Missing Field is %s\n", err.getMissingField()) } } } // function that return struct which implements Error() interface method func validate(name, gender string) error { if name == "" { return &inputError{message: "Name is mandatory", missingField: "name"} } if gender == "" { return &inputError{message: "Gender is mandatory", missingField: "gender"} } return nil } // struct type for holding value type inputError struct { message string missingField string } // impleneting error interface func (i *inputError) Error() string { return i.message } // addtional method for performing necessary action func (i *inputError) getMissingField() string { return i.missingField }
- in below program
Panic and recoverπ
- you can wrap error using
fmt.Errorf("E2: %w", e1)
%w is used to wrap an error.
Defer keywordπ
- defer keyword send any execution to end of function
- deferred function always execute even if surrounding function execution failed abrruptly.
- deferred function will execute before surrounding function returns.
- mutliple defer keyword execute last in first out order
Pointersπ
- pointer declaration
var sptr *string
- pointer can be initialized uisng two way one is
sptr = new("alex")
and second issptr = &name
- for priting the value of pointer you can use astricks operator before variable name
*sptr
effectively dereferencing it. - below is the image of pointer deferencing β
package main
import "fmt"
func pointers() {
// declaration of pointer
var sptr *string
name := "Jayesh"
sptr = &name
var ssptr **string = &sptr
fmt.Println("original variable:", name)
fmt.Println("pointer adress:", sptr)
fmt.Println("referenced variable value:", *sptr)
fmt.Println("double refernced ssptr:", ssptr)
fmt.Println("ssptr value to original pointer:", *ssptr)
fmt.Println("actual ssptr point value derefrenced:", **ssptr)
}
// output
//WARN: this addresses may changes on your system
original variable: Jayesh
pointer adress: 0xc00004c230
referenced variable value: Jayesh
double refernced ssptr: 0xc00000e028
ssptr value to original pointer: 0xc00004c230
actual ssptr point value derefrenced: Jayesh
Structsπ
- struct is collection of fields.
- member of struct can be accessed by dot notation
- struct are pass by value by default.
- if you pass struct to function or new variable a copy of struct is passed
- to manage struct state they need to be pass by reference (pointers)
- structs can be nested.
- nested field are also accessed by dot notation
Slicesπ
-
slices in golang represents three follwing things β
-
default value of slice is usable.
Mapsπ
- default nil value of map cannot be used.
- allowed key types are β
- boolean
- numeric
- string
- pointer
- channel
- interface types
- structs β if all itβs field type is comparable
- array β if the type of value of array element is comparable
- not alllowed key types β
- Slice
- Map
- Function
-
if there are duplicate key the recent value for key is considerd and previous value is discarded
-
you can iterate over map using for range loop
-
map are refrenced data type and is not safe for concurrent use. two variable assigned to each other containing map will point to same map and changes will be reflected wise versa.
func main(){ user := map[string]string{ "name": "John wick", "profession": "assasination", } fmt.Println("original -> ", user) mapPassed(user) fmt.Println("modified -> ", user) } // changes to map will reflect to in parent function to func mapPassed(user map[string]string) { user["status"] = "rich" } // output // map[name:John wick profession:assasination] // map[name:John wick profession:assasination status:rich]
Methodsπ
- methods are receiver function on specific type, eg struct or other function or interface.
- methods can access properties of receiver and other methods on that type.
-
basics syntax
func (receiver receiver_type) some_func_name(arguments) return_values
.type user struct { id int name string email string password string description string } // method syntax func (receiver receiver_type) some_func_name(arguments) return_values func (u *user) validate() error { switch { case !strings.Contains(u.email, "@"): return errors.New("enter proper mail format") case len(u.password) < 8: return errors.New("password should be greater than 8 characters") case u.description == "": return errors.New("descrition should not be empty") } return nil }
-
methods on function type
type Greeting func(name string) string func (g Greeting) exclamation(name string) string { return g(name) + "!" } func (g Greeting) upper(name string) { fmt.Println(strings.ToUpper(name)) } func main() { english := Greeting(func(name string) string { return "Hello, " + name }) fmt.Println(english("ANisus")) fmt.Println(english.exclamation("ANisus")) english.upper("ANisus") }
Interfacesπ
-
basic syntax
-
default value of interface is nil.
- Interface are implemented implicitly
- Helps write more modular and decoupled code between different parts of codebase β It can help reduce dependency between different parts of codebase and provide loose coupling this is application of interface.
- A type implements an interface if it defines all methods of an interface.
-
If that defines all methods of another interface then it implements that interface. In essence, a type can implement multiple interfaces.
-
type asserting syntax
val := i.({type})
- to get concret value of interface type assertion is used in golang.
- An empty interface has no methods , hence by default all concrete types implement the empty interface. If you write a function that accepts an empty interface then you can pass any type to that function