---
# System prepended metadata

title: Go - 04 - Control Statement; Declarations & Types
tags: [Go]

---

# Control Statement; Declarations & Types

## If-then-else

if-then statements require braces

```go
if a == b {
    fmt.Println("a equals b")
} else {
    fmt.Println("a is not equal to b")
}
```

They can start with a short declaration or statement

```go
if err := doSomething(); err != nil {
    return err
}
```

## For loops

1. Explicit control with an index variable

```go
for i := 0; i < 10; i++ {
    fmt.Printf("(%d, %d)\n", i, i * i)

    // prints (0, 0) up to (9, 81)
}
```

Three parts, all optional (initialize, check, increment)
The loop ends when the explicit check fails (e.g., i == 10)

2. Implicit control through the range operator for arrays & slices

```go

// one var: i is an index 0, 1, 2, ...

for i := range myArray {
    fmt.Println(i, myArray[i])
}

// two vars: i is the index, v is a value

for i, v := range myArray {
    fmt.Println(i, v)
}
```

The loop ends when the range is exhausted

3. An infinite loop with an explicit break

```go
i, j := 0, 3
// this loop must be made to stop
for {
    i, j = i + 50, j * j
    fmt.Println(i, j)

    if j > i {
        break // when i = 150, j = 6561
    }
}
```

There is also continue to make an iteration start over

Here's a common mistake:

If you only want range values, you need the blank identifier:

```go
// two vars: _ is the index (ignored),
//          v is the value
for _, v := range myArray {
    fmt.Println(v)
}
```

Sometimes you may not get a compile error for a type mismatch if you use only the one-var format (a slice of ints!)

The _ is an untyped, reusable "variable" placeholder

## Labels and loops

Sometimes we need to break or continue the outer loop
(nested loop for quadratic search)

```go
outer:
    for k := range testItemsMap {
        for _, v := range returnedData {
            if k == v.ID {
                continue outer
            }
        }

        t.Errorf("key not found: %s", k)
    }
```

We need a label to refer to the outer loop

## Switch

It is a shortcut replacing a series of if-then statements

```go
switch a := f.Get(); a {
    case 0, 1, 2:
        fmt.Println("underflow possible")

    case 3, 4, 5, 6, 7, 8:

    default:
        fmt.Println("warning: overload")
}
```

May be empty and do not fall through (break is not required)

## Switch on true

Arbitrary comparisons may be made for an switch with no argument

```go
a := f.Get()

switch {
    case a <= 2:
        fmt.Println("underflow possible")

    case a <= 8:
        // evaluated in order

    default:
        fmt.Println("warning: overload")
}
```

# Packages

Every standalone program has a main package

```go
package main

import "fmt"

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

Nothing is "global"; It's either in your package or in another
It's either at package scope or function scope

## Package-level declarations

You can declare anything at package scope

```go
package secrets

const DefaultUUID = "00000000-0000-0000-0000-000000000000"
var secretKey string

type k8secret struct {
    ...
}

func Do(it string) error {
    ...
}
```

The short declaration (:=) can only be used inside of a function

## Package control visibility

Every name that's capitalized is exported

```go
package secrets
import ...
type internal struct {
    ...
}

func GetAll(space, name string) (map[string]string, error) {
    ...
}
```

## No cycles

A package "A" cannot import a package that imports A

```go
package A
import "B"

// --------

package B
import "A"
```

## Initialization

Items within a package get initialized before main

```go
const A = 1

var B int = C
var C int = A

func Do() error {
    ...
}

func init() {
    ...
}
```

Only the runtime can call `init`, also before `main`

## What makes a good package?

A package should embed deep functionality behind a simple API

```go
package os

func Create(name string) (*File, error)
func Open(name string) (*File, error)

func (f *File) Read(b []byte) (n int, err error)
func (f *File) Write(b []byte) (n int, err error)
func (f *File) Close() error
```

Functions: These are standalone and do not belong to any specific type. They are called independently of any object or instance. For example, Create(name string) and Open(name string) are functions that belong to the os package. They are called directly using their names and passing the required arguments, like os.Create("filename").

Methods: These are associated with a type (like File in your example) and have a receiver (like (f *File)). Methods are called on an instance of that type. For example, Read(b []byte) is a method that is called on an instance of File, like f.Read(b) where f is an instance of File.

The Unix file API is perhaps the best example of this model
Roughly five functions hide a lot of complexity from the user

## Declaration

Six ways to introduce a name:

- Constant declaration with `const`
- Type declaration with type
- Variable declaration with `var` (must have type or initial value, sometimes both)
- Short, initialized variable declaration of any type :=
  only inside a function
- Function declaration with func (methods may only be declared at package level)
- Formal parameters and named returns of a function

## Variable declarations

```go
var a int // 0 by default
var b int = 1
var c = 1 // int
var d = 1.0 // float64

// declaration block
var (
    x, y int
    z    float64
    s    string
)
```

The short declaration operator `:=` has some rules:
1. It can't be used outside of a function
2. It must be used (instead of var) in a control statement (if, etc.)
3. It must declare at least one new variable

```go
err := doSomething()

err := doSomethingElse() // WRONG

x, err := getSomeValue() // OK; err is not redeclared
```

4. It won't be re-used an existing declaration from an outer scope

## Structural typing

It's the same type if it has the same structure or behavior
- arrays of the same size and base type
- slices with the same base type
- maps of the same key and value types
- structs with the same sequence of field names/types
- functions with the same parameter & return types

```go
a := [...]int{1, 2, 3}
b := [3]int{}

a = b // OK
c := [4]int{}

a = c // NOT OK
```

Go uses structural typing in most cases

## Named typing

It's the only the same type if it has the same declared type name

```go
type x int

func main() {
    var a x // x is a defined type; base int

    b := 12 // b defaults to int

    a = b // TYPE MISMATCH

    a = 12 // OK, untyped literal
    a = x(b) // OK, type conversion
}
```

Go uses named typing for non-function user-declared types

---

Prev: [Go - 03 - Arrays, Slices, and Maps](https://hackmd.io/hX6q6PW0TSyqlJlSncl8eQ)
Next: 