# Learning Go: An Idiomatic Approach to Real-World Go Programming

## Chapter 1: Setting Up Your Go Environment

### Installing the Go Tools

[Installing Golang](https://go.dev/doc/install)

#### 1. Downloading Golang

```bash
curl -OL https://golang.org/dl/go{version}.{OS}-{CPU architecture}.tar.gz
```

#### Example

```bash
curl -OL https://golang.org/dl/go1.22.5.linux-amd64.tar.gz
```

#### 2. Create a directory for your Go projects. Example

```bash
make ~/go
```

#### 3. Unzip and copy it

```bash
tar -C /usr/local -xzf go1.22.5.linux-amd64.tar.gz
```

#### 4. Set environments and apply changes

```bash
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

source ~/.bashrc  # Or whichever file you edited
```

#### 5. Verify installation

```bash
go version
```

### The Go Workspace

#### 6. Set up your Go workspace

```bash
mkdir -p $HOME/go/{bin,src,pkg}
```

### The go Command

#### `go run` and `go build`

#### `go run`

```go
package main

import "fmt"

func main() {
  fmt.Println("Hello, World!")
}
```

```bash
go run hello.go
```

#### `go build`

```go
package main

import "fmt"

func main() {
  fmt.Println("Hello, World!")
}
```

```bash
go build hello.go
```

* "-o" option means output name

#### `go third-party packages`

```bash
go install here-path-to-code
```

To install source code like tool, for specific version use @ symbol (@latest). Then downloads, compiles and installs into your `$GOPATH/bin`. To update rerun install command.

#### `go fmt`

```bash
go fmt
```

Automatically reformat your code. `go fmt` in `goimports`. You can download `goimports` with this command

```bash
go install golang.org/x/tools/cmd/goimports@latest
```

```bash
goimports -l -w .
```

### `Linting and Vetting`

Installing linter

```go
go install golang.org/x/lint/golint@latest
```

Run

```go
golint ./...
```

We can run multiple tools together with [golangci-lint](https://golangci-lint.run/)

### Makefiles

Example of Makefile

```makefile
.DEFAULT_GOAL := build

fmt:
    go fmt ./...
.PHONY: fmt

lint: fmt
    golint ./...
.PHONY: lint

vet: fmt
    go vet ./...
.PHONY: vet

build: vet
    go build hello.go
.PHONY: build
```

## Chapter 2: Primitive Types and Declarations

### Literals

Go, like most modern languages, assigns a default zero value to any variable that is declared but not assigned a value.

* Integer literals:

They are normally base ten, but different prefixes are used to indicate other bases: 0b for binary (base two), 0o for octal (base eight), or 0x for hexadecimal (base sixteen).

To make it easier to read longer integer literals, Go allows you to put underscores in the middle of your literal.

```go
package main

import "fmt"

func main() {
    baseTwo := 0b01
    fmt.Println(baseTwo)

    baseEight := 0o1234
    fmt.Println(baseEight)

    baseTen := 1_000_000
    fmt.Println(baseTen)

    baseSixteen := 0x1234
    fmt.Println(baseSixteen)

}
```

* Floating literals

They can also have an exponent specified with the letter e and a positive or negative number (such as 6.03e23)

```go
package main

import "fmt"

func main() {
    exponent := 6.03e23
    fmt.Println(exponent)
}
```

* Rune literals

Unlike many other languages, in Go single quotes and double quotes are not interchangeable

* String literals
  * Double quotes to create an interpreted string literal: `"Greetings and\n\"Salutations\""`
  * Raw string literal.

    ```
    `Greetings and
    "Salutations"`
    ```

### Booleans

```go
var flag false
var isAwesome = true
```

### Numeric Types

| Type name | Value range                                 |
| --------- | ------------------------------------------- |
| int8      | -128 to 127                                 |
| int16     | -32768 to 32767                             |
| int32     | -2147483648 to 2147483647                   |
| int64     | -9223372036854775808 to 9223372036854775807 |
| uint80    | to 255                                      |
| uint160   | to 65536                                    |
| uint320   | to 4294967295                               |
| uint640   | to 18446744073709551615                     |

* A `byte` is an alias for `uint8`;
* On a 32-bit CPU, int is a 32-bit signed integer like an int32. On most 64-bit CPUs, int is a 64-bit signed integer, just like an int6
* uint. It follows the same rules as int, only it is unsigned (the values are always 0 or positive).

| Type name | Largest absolute value                         | Smallest (nonzero) absolute value              |
| --------- | ---------------------------------------------- | ---------------------------------------------- |
| float32   | 3.40282346638528859811704183484516925440e+38   | 1.401298464324817070923729583289916131280e-45  |
| float64   | 1.797693134862315708145274237317043567981e+308 | 4.940656458412465441765687928682213723651e-324 |

[Float numbers in binary](https://en.wikipedia.org/wiki/IEEE_754)

Dividing a nonzero floating point variable by 0 returns `+Inf` or `-Inf` (positive or negative infinity), depending on the sign of the number Dividing a floating point variable set to 0 by 0 returns `NaN` (Not a Number).

Go defines two complex number types. complex64 uses float32 values to represent the real and imaginary part, and complex128 uses float64 values

```go
func main() {
x := complex(2.5, 3.1)
y := complex(10.2, 2)
fmt.Println(x + y)
fmt.Println(x - y)
fmt.Println(x * y)
fmt.Println(x / y)
fmt.Println(real(x))
fmt.Println(imag(x))
fmt.Println(cmplx.Abs(x))
}
```

### A Taste of Strings and Runes

Strings in Go are immutable; you can reassign the value of a string variable, but you cannot change the value of the string that is assigned to it.

The rune type is an alias for the int32 type, just like byte is an alias for uint8.

### Explicit Type Conversion

Go doesn't allow automatic type promotion between vari ables. You must use a type conversion when variable types do not match. Even different-sized integers and floats must be converted to the same type to interact.

```go
var x int = 10
var y float64 = 30.2
var z float64 = float64(x) + y
var d int = x + int(y)
```

### var Versus `:=`

`var` keyword to declare

```go
var x int = 10

var x = 10

var x int

var x, y int = 10, 20

var x, y int

var x, y = 10, "hello"

var (
    x int
    y = 20
    z int = 30
    d, e = 40, "hello"
    f, g string
)
```

Short declaration

```go
x := 10 // var x = 10
x, y := 10, "hello" // var x, y = 10, "hello"
```

The `:=` operator can do one trick that you `cannot` do with `var`: it allows you to `assign` values to existing variables, too.

### `const`

They can only hold values that the compiler can figure out at compile time. This means that they can be assigned:

* Numeric literals
* true and false
* Strings
* Runes
* The built-in functions complex, real, imag, len, and cap
* Expressions that consist of operators and the preceding values

Go doesn't provide a way to specify that a value calculated at runtime is immutable.

### Typed and Untyped Constants

Constants can be typed or untyped.

```go
// Untyped
const x = 10

var y int = x
var z float64 = x
var d byte = x

// Types
const typedX int = 10
// This constant can only be assigned directly to an int
```

### Unused variables

Go requirement is that every declared local variable must be read. It is a compile-time error to declare a local variable and to not read its value.

Perhaps surprisingly, the Go compiler allows you to create unread constants with const.

### Naming Variables and Constants

```go
_0 := 0_0
_𝟙 := 20
π := 3
ａ := "hello" // Unicode U+FF41
fmt.Println(_0)
fmt.Println(_𝟙)
fmt.Println(π)
fmt.Println(ａ)

fmt.Println("Using look-alike code points for variable names")
ａ := "hello"   // Unicode U+FF41
a := "goodbye" // standard lowercase a (Unicode U+0061)
fmt.Println(ａ)
fmt.Println(a)
```

Idiomatic Go doesn't use snake case (names like index\_counter or number\_tries). Instead, Go uses camel case (names like indexCounter or numberTries) when an identifier name consists of multiple words.

## Chapter 3: Composite Types

### Arrays - Too rigid to use Directly

```go
var x [3]int

var x = [3]int{10, 20, 30}

var x = [12]int{1, 5: 4, 5, 10: 100, 15}

var x = [...]int{10, 20, 30}

var x = [...]int{1, 2, 3}
var y = [3]int{1, 2, 3}
fmt.Println(x == y)

var x [2][3]int

var x = [3]int{1, 2, 3}
x[0]=10
fmt.Println(x[2])
fmt.Println(len(x))
```

Declared to be \[3]int a different type from an array that’s declared to be \[4]int. This also means that you cannot use a variable to specify the size of an array, because types must be resolved at compile time, not at runtime.

What’s more, you can’t use a type conversion to convert arrays of different sizes to identical types. Because you can’t convert arrays of different sizes into each other, you can’t write a function that works with arrays of any size and you can’t assign arrays of different sizes to the same variable.

### Slices

Holds a sequence of values, a slice is what you should use. What makes slices so useful is that the length is not part of the type for a slice. This removes the limitations of arrays. We can write a single function that processes slices of any size

> Using \[…] makes an array. Using \[] makes a slice

```go
var x = []int{10, 20, 30} // Initializing with values
var x = []int{1, 5: 4, 6, 10: 100, 15} // Initializing with sparse slice
var x = [][]int{{10}, {100, 200}} // Two-dimensional slice

x[0] = 10 // Accessing elements

var x []int // Declaring
```

`var x []int`

This creates a slice of ints. Since no value is assigned, x is assigned the zero value for a slice, which is something we haven’t seen before: `nil`

`A nil slice` contains nothing.

A slice is the first type we’ve seen that `isn’t comparable`. The only thing you can compare `a slice` with is `nil`:

```go
var x []int
fmt.Println(x == nil) // true
```

#### len

When you pass a nil slice to len, it returns 0.

```go
var x []int
fmt.Println(len(x)) // 0

var x = []int{10, 20, 30}
fmt.Println(len(x)) // 3
```

#### append

Every time you pass a parameter to a function, Go makes a copy of the value that’s passed in. Passing a slice to the append function actually passes a copy of the slice to the function. The function adds the values to the copy of the slice and returns the copy. You then assign the returned slice back to the variable in the calling function.

```go
var x []int
x = append(x, 10)

var x = []int{1, 2, 3}
x = append(x, 4)
x = append(x, 4, 5, 6)

y := []int{20, 30, 40}
x = append(x, y...)
```

#### Capacity

Every slice has a *capacity*, which is the number of consecutive memory locations reserved. Each value added increases the length by one. When the length reaches the capacity, there’s no more room to put values. If you try to add additional values when the length equals the capacity, the *append* function uses the Go runtime to allocate a new slice with a larger capacity. The values in the original slice are copied to the new slice, the new values are added to the end, and the new slice is returned.

> The Go runtime provides services like memory allocation and garbage collection, concurrency support, networking, and implementations of built-in types and functions.

The rules as of Go 1.14 are to double the size of the slice when the capacity is less than 1,024 and then grow by at least 25% afterward. Just as the built-in len function returns the current length of a slice, the built-in cap function returns the current capacity of a slice.

```go
var x []int
fmt.Println(x, len(x), cap(x))
x = append(x, 10)
fmt.Println(x, len(x), cap(x))
x = append(x, 20)
fmt.Println(x, len(x), cap(x))
x = append(x, 30)
fmt.Println(x, len(x), cap(x))
x = append(x, 40)
fmt.Println(x, len(x), cap(x))
x = append(x, 50)
fmt.Println(x, len(x), cap(x))
```

#### make

`make` function allows us to specify the type, length, and, optionally, the capacity.

```go
x := make([]int, 5)
fmt.Println(x, len(x), cap(x))
```

We can also specify an initial capacity with make:

```go
x := make([]int, 5, 10)
fmt.Println(x, len(x), cap(x))
```

You can also create a slice with zero length, but a capacity that’s greater than zero:

```go
x := make([]int, 0, 10)
fmt.Println(x, len(x), cap(x))
```

#### Declaring your slice

The primary goal is to minimize the number of times the slice needs to grow.

You can create a slice using an empty slice literal:

```go
var x []int // nil
fmt.Println(x, len(x), cap(x), x == nil)

var y = []int{} // non-nil
fmt.Println(y, len(y), cap(y), y == nil)
```

#### Slicing Slices

A *slice expression* creates a slice from a slice.

```go
x := []int{1, 2, 3, 4}
y := x[:2]
z := x[1:]
d := x[1:3]
e := x[:]
fmt.Println("x:", x)
fmt.Println("y:", y)
fmt.Println("z:", z)
fmt.Println("d:", d)
fmt.Println("e:", e)
```

> Slices share storage sometimes. When you take a slice from a slice, you are not making a copy of the data.

```go
x := []int{1, 2, 3, 4}
y := x[:2]
z := x[1:]
x[1] = 20
y[0] = 10
z[1] = 30
fmt.Println("x:", x)
fmt.Println("y:", y)
fmt.Println("z:", z)
```

Changing x modified both y and z, while changes to y and z modified x. Slicing slices gets extra confusing when combined with *append*.

```go
x := []int{1, 2, 3, 4}
y := x[:2]
fmt.Println(cap(x), cap(y))
y = append(y, 30)
fmt.Println("x:", x)
fmt.Println("y:", y)
```

The full slice expression protects against appen

```go
x := make([]int, 0, 5)
x = append(x, 1, 2, 3, 4)
y := x[:2]
z := x[2:]
fmt.Println(cap(x), cap(y), cap(z))
y = append(y, 30, 40, 50)
x = append(x, 60)
z = append(z, 70)
fmt.Println("x:", x)
fmt.Println("y:", y)
fmt.Println("z:", z)
```

#### copy

If you need to create a slice that’s independent of the original, use the built-in copy function.

```go
x := []int{1, 2, 3, 4}
y := make([]int, 4)
num := copy(y, x)
fmt.Println(y, num)
```

The copy function takes two parameters. The first is the destination slice and the second is the source slice.

> The capacity of x and y doesn’t matter; it’s the length that’s important.

```go
x := []int{1, 2, 3, 4}
y := make([]int, 2)
num = copy(y, x)
```

You can use copy with arrays by taking a slice of the array. You can make the array either the source or the destination of the copy

```go
x := []int{1, 2, 3, 4}
d := [4]int{5, 6, 7, 8}
y := make([]int, 2)
copy(y, d[:])
fmt.Println(y)
copy(d[:], x)
fmt.Println(d)
```

### Strings and Runes and Bytes

Go uses a sequence of bytes to represent a string.

> Go source code is always written in UTF-8. Unless you use hexadecimal escapes in a string literal, your string literals are written in UTF-8.

```go
var s string = "Hello there"
var s2 string = s[4:7]
var s3 string = s[:5]
var s4 string = s[6:]

s = "Hello 🌞"
s2 = s[4:7]
s3 = s[:5]
s4 = s[6:]
fmt.Println(s, "len:", len(s))
fmt.Println(s2, s3, s4)
```

This code `(len(s))` prints out 10, not 7, because it takes four bytes to represent the sun with smiling face emoji in UTF-8.

> Even though Go allows you to use slicing and indexing syntax with strings, you should only use it when you know that your string only contains characters that take up one byte.

A single rune or byte can be converted to a string:

```go
var a rune = 'x'
var s string = string(a)
var b byte = 'y'
var s2 string = string(b)
```

A string can be converted back and forth to a slice of bytes or a slice of runes.

```go
var s string = "Hello, "
var bs []byte = []byte(s)
var rs []rune = []rune(s)
fmt.Println(bs)
fmt.Println(rs)
```

### Maps

```go
var nilMap map[string]int
```

In this case, nilMap is declared to be a map with string keys and int values. The zero value for a map is `nil`. A nil map has a length of 0. Attempting to read a nil map always returns the zero value for the map’s value type. However, attempting to write to a nil map variable causes a panic.

We can use a := declaration to create a map variable by assigning it a map literal:

```go
totalWins := map[string]int{} // empty-map
fmt.Println(len(totalWins), totalWins)

teams := map[string][]string{ // non-empty map
    "Orcas":   []string{"Fred", "Ralph", "Bijou"},
    "Lions":   []string{"Sarah", "Peter", "Billie"},
    "Kittens": []string{"Waldo", "Raul", "Ze"},
}
fmt.Println(len(teams), teams)

ages := make(map[int][]string, 10) // map with default-size
fmt.Println(len(ages), ages)
```

* Maps automatically grow as you add key-value pairs to them.
* If you know how many key-value pairs you plan to insert into a map, you can use make to create a map with a specific initial size.
* Passing a map to the len function tells you the number of key-value pairs in a map.
* The zero value for a map is nil.
* Maps are not comparable. You can check if they are equal to nil, but you cannot check if two maps have identical keys and values using == or differ using !=.

The key for a map can be any `comparable type`. This means you cannot use a slice or a map as the key for a map.

Use a map when the order of elements doesn’t matter. Use a slice when the order of elements is important.

> What is a Hash Map?
>
> A hash map does fast lookups of values based on a key. Internally, it’s implemented as an array. When you insert a key and value, the key is turned into a number using a hash algorithm. These numbers are not unique for each key. The hash algorithm can turn different keys into the same number. That number is then used as an index into the array. Each element in that array is called a bucket. The key-value pair is then stored in the bucket. If there is already an identical key in the bucket, the previous value is replaced with the new value. Each bucket is also an array; it can hold more than one value. When two keys map to the same bucket, that’s called a collision, and the keys and values for both are stored in the bucket.

#### Reading and Writing a Map

```go
totalWins := map[string]int{}
totalWins["Orcas"] = 1
totalWins["Lions"] = 2
fmt.Println(totalWins["Orcas"])
fmt.Println(totalWins["Kittens"])
totalWins["Kittens"]++
fmt.Println(totalWins["Kittens"])
totalWins["Lions"] = 3
fmt.Println(totalWins["Lions"])
```

#### The comma ok Idiom

```go
m := map[string]int{
"hello": 5,
"world": 0,
}
v, ok := m["hello"]
fmt.Println(v, ok)
v, ok = m["world"]
fmt.Println(v, ok)
v, ok = m["goodbye"]
fmt.Println(v, ok)
```

#### Deleting from Maps

```go
m := map[string]int{
"hello": 5,
"world": 10,
}
delete(m, "hello")
```

If the key isn’t present in the map or if the map is nil, nothing happens. The delete function doesn’t return a value.

#### Using Maps as Sets

```go
intSet := map[int]bool{}
vals := []int{5, 10, 2, 5, 8, 7, 3, 9, 1, 2, 10}
for _, v := range vals {
    intSet[v] = true
}
fmt.Println(len(vals), len(intSet))
fmt.Println(intSet[5])
fmt.Println(intSet[500])
if intSet[100] {
    fmt.Println("100 is in the set")
}
```

Some people prefer to use `struct{}` for the value when a map is being used to implement a set. The advantage is that an empty struct uses `zero bytes`, while a boolean uses `one byte`. The disadvantage is that using a `struct{}` makes your code more `clumsy`. You have a less obvious assignment, and you need to use `the comma ok idiom` to check if a value is in the set.

```go
intSet := map[int]struct{}{}
vals := []int{5, 10, 2, 5, 8, 7, 3, 9, 1, 2, 10}
for _, v := range vals {
    intSet[v] = struct{}{}
}
if _, ok := intSet[5]; ok {
    fmt.Println("5 is in the set")
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://go.realtemirov.uz/readme.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
