Studying GO by the book and documentation
- 🟡 https://www.youtube.com/watch?v=YS4e4q9oBaU
- https://www.youtube.com/watch?v=jFfo23yIWac
- https://www.amazon.com.br/Go-Programming-Language-Brian-Kernighan
go mod init example/hello
So just add the main like below:
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Let's run it:
go run .
var foo int = 30
var foo2 int
foo3 := 31
- Lower Case first letter: Package Scope
- Upper Case first letter: Export from Package / Exposed
- destinationType(variable)
- use strconv package for strings
var b bool = true
var b int = 1
var b int8 = 1
var b int16 = 1
var b int32 = 1
var b int64 = 1
var b uint = 1
var b uint8 = 1
var b uint16 = 1
var b uint32 = 1
var b uint64 = 1
var b float32 = 1
var b float64 = 1
var b complex64 = 5+2i
var b complex128 = 5+2i
var s string = ""
var ch rune = 'a'
// same way
const a int = 3
const a = 3
const (
a = iota // a = 0
b // b = 1
c // c = 2
)
const (
a = iota * 2 // a = 0 * 2 = 0
b // b = 1 * 2 = 2
c // c = 2 * 2 = 4
)
const (
a = iota // a = 0
b // b = 1
)
const (
c = iota // c = 0, not 2!
d // d = 1
)
In Go arrays are types, if you copy a array to another variable, it will be a new array, not a reference.
len()
returns the length of the array/slicecap()
returns the capacity of the array/slice- You can declare one array in three ways:
var a [3]int
,a := [3]int{1, 2, 3}
ora := [...]int{1, 2, 3}
- You can declare a slice in two ways:
var a []int
ora := []int{1, 2, 3}
(Literal Style) - You can use make to create a slice:
make([]int, 3, 4)
where 3 is the length and 4 is the capacity (Via make) - Or you can create a slice form an existing array:
a := [3]int{1, 2, 3}
andb := a[:]
orb := a[1:2]
(Via existing array)
append() is a function that can be used to append a slice to another slice, for example:
a := []int{1, 2, 3}
b := []int{4, 5, 6}
a = append(a, b...)
Some examples
Some examples:
````go
// fixed length
grades := [2]int{1, 2}
fmt.Printf("Grades %v", grades)
// also
grades2 := [...]int{1, 2, 3}
fmt.Printf("Grades %v", grades2)
// also
var students [3]string
fmt.Printf("Students %v", students)
// get the length
fmt.Printf("Length %v", len(students))
// 3d array
var matrix [3][3]int = [3][3]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
fmt.Printf("Matrix %v\n", matrix)
// copies
a := [...]int{1, 2, 3}
b := a
b[1] = 5
fmt.Printf("a %v b %v\n", a, b)
// prints a [1 2 3] b [1 5 3]
c := &a
c[1] = 5
fmt.Printf("a %v c %v\n", a, c)
// prints a [1 5 3] c &[1 5 3]
// print the pointer value
fmt.Printf("*c: %T %v / c: %T %v\n", *c, *c, c, c)
// Slices
z := []int{1, 2, 3}
fmt.Printf("slice 1: %v len: %v\n", z, len(z))
z1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
z2 := z1[:]
z3 := z1[1:4]
z3[0] = 0
fmt.Printf("z1 %v z2 %v z3 %v\n", z1, z2, z3)
// make
sl := make([]int, 3)
fmt.Printf("%v - len %v\n", sl, len(sl))
//capacity
sl2 := make([]int, 3, 4)
fmt.Printf("%v - len %v - cap %v\n", sl2, len(sl2), cap(sl2))
sl2 = append(sl2, 5)
sl2 = append(sl2, 6)
fmt.Printf("%v - len %v - cap %v\n", sl2, len(sl2), cap(sl2))
// testing append with common arrays
sl10 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("bafore append in normal -> %v, cap %v, len %v\n", sl10, cap(sl10), len(sl10))
sl10 = append(sl10, 10, 11, 12, 13)
fmt.Printf("after append in normal -> %v, cap %v, len %v\n", sl10, cap(sl10), len(sl10))
You can use the spread operator to append a slice to another slice for example
appednd(sl1, []int{1, 2, 3, 4, 5, 6, 7, 8, 9}...)
In Go, a map is a built-in data type that provides a way to store unordered key-value pairs. It offers efficient lookup, addition, and deletion operations. The keys within a map are unique and can be of any type that is comparable (e.g., int, float, string, etc.), while values can be of any type.
Using Composite Literal
This is a concise way to declare and initialize a map with a predefined set of key-value pairs:
m1 := map[string]int{
"Texas": 10,
"California": 5,
}
m1["other"] = 8
fmt.Println(m1, len(m1))
Using make
The make function provides a way to create a map. Optionally, you can provide an initial space allocation hint:
m2 := make(map[string]int, 10)
m2["Test"] = 1
m2["OtherTest"] = 2
fmt.Println(m2, len(m2))
The number 10 here is a hint to the compiler about the initial allocation size. It does not limit the number of items the map can store.
Add/Update
To add or update a key-value pair in the map:
m1["NewKey"] = 12
Delete
delete(m2, "Test")
fmt.Printf("After deleting m2: %v \n", m2)
Check Existence
When accessing a map, you can retrieve both the value and a boolean indicating whether the key was present:
v1, ok1 := m2["OtherTest"]
v2, ok2 := m2["OtherTestWrong"]
fmt.Printf("Found v1: %v ok1: %v\n", v1, ok1)
fmt.Printf("Not found v2: %v ok2: %v\n", v2, ok2)
A common idiom to check if a key exists is:
_, exists := m2["OtherTestWrong"]
if exists {
fmt.Println("exists")
} else {
fmt.Println("It doesn't exist")
}
func changeMap(m map[string]int) {
m["Changed"] = 100
}
func main() {
m := map[string]int{"Original": 50}
changeMap(m)
fmt.Println(m) // Outputs: map[Changed:100 Original:50]
}
Iterating over key and value pairs
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
for key, value := range m {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
Iterating over only keys:
for key := range m {
fmt.Println("Key:", key)
}
Iterating over the values
for _, value := range m {
fmt.Println("Value:", value)
}
Maps are powerful data structures in Go that allow you to store and manage key-value pairs efficiently. By understanding the basic operations and behavior of maps, you can effectively use them in various applications.
In Go, a struct is a composite data type that groups together zero or more fields (properties) with differing data types. Structs are incredibly versatile and are often used as the foundation for creating complex data models in Go.
Anonymous Structs
Structs don't necessarily need to have a defined name. You can create an anonymous struct, declaring it on-the-fly:
aDeveloper := struct{ name string }{name: "Wilson"}
fmt.Println(aDeveloper)
Structs are Value Types
By default, when you assign one struct to another or pass it to a function, the entire struct is copied. This behavior is consistent with Go's other value types like int and float64.
anotherDeveloper := aDeveloper
anotherDeveloper.name = "Martin Fowler"
fmt.Println(aDeveloper) // Wilson
fmt.Println(anotherDeveloper) // Martin Fowler
Passing Structs by Reference
If you don't want to work with a copy, you can pass a pointer to the struct:
anotherDeveloper2 := &aDeveloper
anotherDeveloper2.name = "Martin Fowler"
fmt.Println(aDeveloper) // Martin Fowler
fmt.Println(anotherDeveloper2) // Martin Fowler
Declaring Struct Types
type Developer struct {
Name string
Age int
Stack []string
}
dev := Developer{Name: "Wilson", Age: 30, Stack: []string{"Go Lang", "C#", "Python", "JS/TS", "Azure", ".Net", "React.js", "Next.js"}}
fmt.Println(dev)
Embedding
Go doesn't have the traditional class inheritance that you'd find in object-oriented languages, but it offers a type embedding mechanism. This allows you to include one struct type inside another, which promotes code reuse and a form of polymorphism.
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
CanFly bool
}
Embedded types can be initialized either explicitly:
bird := Bird{Animal: Animal{Name: "Name", Origin: "BR"}, CanFly: true}
fmt.Println(bird)
Or implicitly:
bird2 := Bird{}
bird2.Name = "Bird 2"
bird2.Origin = "US"
bird2.CanFly = true
fmt.Println(bird2)
Struct field tags are annotations attached to struct field declarations. They are commonly used for metadata, such as configuring serialization and validation methods:
type City struct {
Name string `required max:"100" json:"name,omitempty"`
State string `json:"state,omitempty"`
}
r := reflect.TypeOf(City{})
field, _ := r.FieldByName("Name")
fmt.Println(field.Tag) //required max:"100" json:"name,omitempty"
Structs in Go provide a flexible way to organize and model your data. They form the foundation for creating user-defined types and can be combined, embedded, or extended in versatile ways to suit the specific requirements of your program.