Variables

Learning notes from reading Go book.

Defining Variables

Go has two ways of defining types. The rules outlined are:

  absoluteZero := -459.67 // Implicit
  var hardWater int = 0 // Explicit
  gassyWater := int32(100) // Mixed

Convert Types

  fmt.Printf("%T\n", int64(gassyWater)) // int64

Naming Variables

Capitalizing a variable has meeting:

const

The keyword for constant variables is const. Constants can be declared with or without a type. Those declared with a type will not be coerced into another type.

const (
  year = 365 // untyped
  leapYear = int32(366) // typed
)

fmt.Println(int64(2) _ year) // 730
// Throws an error:
fmt.Println(int64(2) _ leapYear) // 732

Arrays

Arrays are defined with a size, a type, and then values.

Arrays cannot change size! See Slices

colours := [3]string{"Red", "Green", "Blue"}
fmt.Println(colours[0]) // Red

Convert an Array to a slice:

colourSlice := colours[:]
colourSlice = append(colourSlice, "Yellow")
fmt.Println(colourSlice) // [Red Green Blue Yellow]

Slices

Slices are more how I think of Arrays. Dynamically resizable. Less C-like.

fish := []string{"Goldfish", "Bass", "Pike"}
fish = append(fish, "Salmon")
fmt.Println(fish[1]) // Bass
fmt.Println(len(fish)) // 4

TODO: How to shift, pop, slice?

Maps

Maps are like hashes.

foods := map[string]string{"Orange": "Fruit", "Lettuce": "Vegetable"}
fmt.Println(foods["Orange"]) // Fruit

Control Flow

Conditional Flow

Conditionals do not require parenthesis, and GO uses else if.

if balance < 0 {
  // In debt.
} else if balance == 0 {
  // flat broke
} else {
  // Some cash.
}

Switches can be used on strngs:

for _, colour := range colours {
  switch colour {
    case "Blue":
      fmt.Println(colour, " is my favorite")
    case "Black":
      fmt.Println(colour, " is hot in the sun!")
    default:
      fmt.Println(colour, " is a colour")
  }
}

Anonymous switch can be used for ranges:

randInt := rand.Intn(100)
switch {
  case randInt < 50:
    fmt.Println("Low", randInt)
  case randInt >= 50:
    fmt.Println("High ", randInt)
}

Loops

Iterating over a Map:

for k, v := range foods {
  fmt.Printf("%q is a %q\n", k, v) // Orange is a Fruit\n
}

Getting just the keys by omitting the value variable:

for k := range foods {
  fmt.Println(k) // Orange
}

For loops are similar to other languages with 3 parts:

for i := 0; i < 5; i++ {
  // Do something.
  continue; // Skips this loop.
  break; // Exits loop
}

Checking key existence requires a second return value:

orangeValue, orangeOk := foods["Orange"]
fmt.Printf("%q => %t\n", orangeValue, orangeOk) // "Fruit" => true
notFoundValue, notFoundOk := foods["notFound"]
fmt.Printf("%q => %t\n", notFoundValue, notFoundOk) // "" => false

Deleting keys is a function:

vegs := foods
delete(vegs, "Orange")
fmt.Println(vegs)

Strings

Backticks are how to define strings with no interpretation:

fmt.Println(`A "string" literal!\n`) // A "string" literal!\n

Strings are added to contatenate.

pet := "little lamb"
fmt.Println("Mary had a " + pet) // Mary had a little lamb

strings

fmt.Println(strings.ToUpper("Mark the Shark")) // MARK THE SHARK
fmt.Println(strings.ToLower("Mark the Shark")) // mark the shark
fmt.Println(strings.Contains("Mark the Shark", "the")) // true
fmt.Println(len("Mark the Shark")) // 14
fmt.Println(Strings.Join(fish, ", "))
fmt.Println(strings.ReplaceAll(pet, "l", "m")) // mittme mamb

In fmt.Printf, some characters have special meaning

fmt.Printf("%q", foods) // map["Lettuce":"Vegetable" "Orange":"Fruit"]
fmt.Printf("%T, %T, %T\n", absoluteZero, hardWater, gassyWater) // float64, int, int32

strconv

strconv can be use to convert strings to numbers.

parsedFloat, _ := strconv.ParseFloat("12.34", 64)
fmt.Printf("%T\n", parsedFloat) // float64

sort

Can sort a list of strings:

sort.Strings(fish)
fmt.Println(strings.Join(fish, ", ")) // Bass, Goldfish, Pike, Salmon

IMPORTANT Sorts in Go modify the existing array. They do not make a copy. Beware!

Panics

Panics are exceptions. Most of the time you should be anticipating a panic, but if you are, you can use recover() to catch the issue.

func catchPanic() {
  defer func() {
    if err := recover(); err != nil {
      fmt.Println("Panic occurred: ", err)
    }
  }()
  panic("This is a panic!")
}

catchPanic() // Panic occurred: This is a panic!

Packages

Packages in go similar to a class, but more functional than OOP.

Just to reiterate, any TitleCase variables or methods will be exported, while lowercase will not. This applies to types, functions, and variables defined at the package scope.

Take, for example, a beverage package:

package beverage // LOWER CASE!

// Beverage is an example of a type in Go.
type Beverage struct { // UPPER CASE!
  Name string
  hot bool
}

// NewBeverage is like a class method which will hang off of Beverage.
func New(name string, hot bool) *Beverage {
  return &Beverage{
    Name: name,
    Hot: hot,
  }
}

// Print is like an instance method.
func (b *Beverage) Print() {
  fmt.Printf("Beverage \"%s\" is served hot: %t\n", b.Name, b.Hot)
}

It appears, at first glass, that Beverage.New() would be a function, but it is not. In fact, New() is a function within the beverage package.

To use Beverage:

package main

import "beverage"

func main() {
  c := beverage.New("Coffee", true) // Package name, not type name.
  c.Print() // Beverage "Coffee" is served hot: true
  m := beverage.New("Mountain Dew", true)
  m.Hot = false // Hot Mt. Dew? Gross!
  m.Print() // Beverage "Mountain Dew" is served hot: false
}

Methods

Go supports a variadic function, accepting 0 or more arguments.

func sayHello(names ...string) {
  for _, n := range names {
    fmt.Printf("Hello, %s!\n", n)
  }
}

Variadic functions can also accept named arguments in addition to the catch-all, but the variadic value must be the last argument.

func join(delimiter string, values ...string) string {
  // do stuff.
}

If you’re passing a slice as arguments to a function, you can expand the arguments with ellipses:

names := []string{"Sammy", "Jessica", "Drew"}
line = join(",", names...)

Defer

Defer defines a function which is called after the End of a given function. If multiple defer functions are defines, they are executed in reverse order.

func main() {
  defer fmt.Println("Bye")
  defer fmt.Println("Goodbye")
  fmt.Println("Hi")
} // Hi\nGoodbye\nBye

Sample