This is a repo to store my golang progress on golang.
I wish someday I'd be able to work with this great language
- Class annotations:
-
Switches allows us to evaluate expressions and constant values
package main import "fmt" func main() { a := 1 switch a { // can only use const expressions to evaluate case 10: fmt.Println("equals to 10") } switch { // can use dynamic expressions to evaluate case a < 10: fmt.Println("less than 10") case a == 10: fmt.Println("equals to 10") default: fmt.Println("more than 10") } }
-
Maps
package main import "fmt" func main() { myMap := make(map[string]int) myMap["aluno0"] = 10 myMap["aluno1"] = 40 myMap["aluno3"] = 50 myMap["aluno2"] = 60 for key, value := range myMap { // it doesn't prints sorted fmt.Printf("%s: %d\n", key, value) } fmt.Println(myMap["aluno5"]) // prints 0 fmt.Println(myMap) }
-
*Reader | *Scanner
-
Reader reads a single value (I have to use a specific function depending on what kind of value I'm trying to read)
reader := bufio.NewReader(os.Stdin) input, _ := reader.ReadLine("\n")
-
Scanner can read many values (or a single as well):
scanner := bufio.NewScanner(os.Stdin) scanner.Scan() text := scanner.Text()
-
-
Implement something with Flags (package)
-
Methods:
type Rectangle struct {} // This r is called "reciever" || it can be a pointer as well func(r Rectangle) printArea() { fmt.Println("Test") }
-
Interfaces
- In order to implement this interface my struct should implement all of the methods
type IFigure { area() float32 }
- Go has a concept of empty interface, anything automatically implements it:
func main(){ // implements any type - kindof dynamic typing in go var i interface {} i = 42 fmt.Println("Value:", i) i = "Hello" fmt.Println("Value:", i) } // can only use type assertion on interfaces var x interface{} = "foo" var s string = x.(string) fmt.Println(s) // "foo" s, ok := x.(string) fmt.Println(s, ok) // "foo true" n, ok := x.(int) fmt.Println(n, ok) // "0 false" fmt.Println(n.(type)) n = x.(int) // ILLEGAL
-
Generics
// K may be integer, V may be int, float64, string type IndexTable[K int, V int|float64|string] struct { ket K values []V } // I am passing this explicit type because compiler can't understand it sometimes table := IndexTable[int, int] {1, []int {1,2,3,4}} // In functions: func DoSomething[T int|float64](x, y T) T{ return x + y } // I can create an interface containing the types I admit (type set) type Number interface { int | float64 } func DoSomething[Number](x, y T) T{ return x + y }
-
Comparable In GO, we can use 'comparable' as an identifier of primitive types that can be both compared and used as generic type.
-
Modularization In Go, we implement packages as directories: package university -> ./university things we want to export in package should begin with capital first letter
package temperature // It begins with capital letter func CelsiusToFahrenheit(t float64) float64 { return (t*9/5) + 32 } //------------ TO USE IT ------------ package main import ( "fmt" "temperature" ) func main() { temp := temperature.CelsiusToFahrenheit(10.2) fmt.Println(temp) }
Modules simplifies dependecies
go.mod - lists every package program needs to work
go mod init module-name
// generates it on ./go.mod
module module-name
go 1.20 // go version
go mod tidy // check program and insert dependency requirements on go.mod -> generates a go.sum (it checks integrity)
-
Testing Go has a native tool focused on tests (mainly unity tests); There are two main tests - basic (one input produces one output) and tabled (set of test cases submitted to the same function [similar to theory]); Testing should be apart from application;
Go test files should:
- belong to the same directory and package as the code they test
- be named ending with _test.go
- import package testing
test functions names should begin with Test:
// *testing.T is a generic testing pointer, it provides many possibilities func TestCelsiusToGahrenheit(t *testing.T) { cTemp := 29.0 fTemp := 84.2 // Fatal kills execution // Error prints error and keeps going with test cases if(CelsiusToFahrenheit(cTemp) != fTemp) { t.Fatal("\nError on converting from Celsius to Fahrenheit") } else { t.Log("\nConverting from Celsius to Fahrenheit: correct") } } // In order to test many cases, we create a slice to store param and expected value and loop over it
Running:
- run -> recieves a function to test (if we dont specify this flag, all test functions will be runned) run="none" // disable test functions in test files (useful when working with benchmark) -bench -> recieves a function to test (if we dont specify this flag, all test functions will be runned) bench="." // runs all benchmarks - benchmem -> show information about memmory allocation - v -> verbose test mode go run test -run=TestCelsiusToFahrenheit go run test -run=TestCelsiusToFahrenheit -v
Go allow us to run tests in parallel (by default it runs sequentially):
func TestCelsiusToFahrenheit(t *testing.T) { t.Parallel() // <====================== it will make this test run parallel to next function // Test code }
-
Benchmarking Go benchmark files should:
- belong to the same directory and package as the code they test
- be named ending with _test.go
- import package testing
- recieve b *testing.B pointer (actually this is not mandatory)
OBS.:
- b.N < as much as possible in 1 second (comes from pointer)
- b.ResetTimer() should be called at the beginning to reset in each function (generate a fair result)
-
HTTP Under GO https://pkg.go.dev/net/http
We can create servers and clients
// SERVER package main import ( "fmt" "log" "net/http" ) func sayHello(res http.ResponseWriter, req *http.Request) { res.Write([]byte("Hello, stranger")) // fmt.Fprint(res, "Hello, stranger") -> mesmo comportamento } func printNow(res http.ResponseWriter, req *http.Request) { currentTime := time.Now() fmt.Fprint(res, currentTime.Format("02/01/2006 15:04:05")) } func main() { // We can custom http server through http object server := &http.Server { Addr: "localhost:4000", WriteTimeout: 10 * time.Second, } http.HandleFunc("/", sayHello) http.HandleFunc("/now", printNow) //log.Fatal(http.ListenAndServe("localhost:4000", nil)) // Listen to default http server log.Fatal(server.ListenAndServe("localhost:4000", nil)) // Listen to my custom http server }
// CLIENT package main import ( "fmt" "io" "log" "net/http" ) const url = "https://www.boredapi.com/api/activity" // Using package method func main() { // GET, HEAD, POST, PUT, DELETE if res, err := http.Get(url); err != nil { log.Fatal(err) } else { contents, _ := io.ReadAll(res.Body) defer res.Body.Close() fmt.Println(string(contents)) } } // Creating request manually func main() { req, _ := http.NewRequest("GET", url, nil) if res, err := http.DefaultClient.Do(req); err != nil { log.Fatal(err) } else { contents, _ := io.ReadAll(res.Body) defer res.Body.Close() fmt.Println(string(contents)) } } // We can create custom clients as well overloading config func main(){ client := &http.Client{Timeout: 3 * time.Second} // OVERLOAD CLIENT CONFIG if res, err := client.Get(url); err != nil { log.Fatal(err) } else { contents, _ := io.ReadAll(res.Body) defer res.Body.Close() fmt.Println(string(contents)) } } // Sending a POST request const endpoint = "https://httpbin.org/post" func main() { data := strings.NewReader(`{ "activity": "Learn to play a new instrument", "type": "music" }`) if res, err := http.Post(endpoint, "application/json", data); err != nil { log.Fatal(err) } else { contents, _ := io.ReadAll(res.Body) defer res.Body.Close() fmt.Printf("%s", contents) } } // Dealing with http errors res, err := http.Get(url) switch { case 400 <= res.StatusCode && res.StatusCode < 500: fmt.Println("Client error") case 500 <= res.StatusCode && res.StatusCode < 600: fmt.Println("Server error") } // Mapping json response to Structured Data const url = "https://www.boredapi.com/api/activity" type Activity struct { Activity string Type string Participants int } contents, _ := io.ReadAll(res.Body) defer res.Body.Close() var a Activity err := json.Unmarshal(contents, &a) // Maps to data structure if err != nil { log.Fatal(err) } else { fmt.Printf("What? %s\n", a.Activity) fmt.Printf("What kind? %s\n", a.Type) fmt.Printf("How many? %d\n", a.Participants) }
-