If-Statements

If-Statements:
- Initializers: Allows you to generate a statement to set-up for a comparison
- Variables in an if-statement are block-scoped
- Comparison operators (primarily for numeric types):
  - less-than (<)
  - greater-than (>)
  - less-than-or-equal-to (<=)
  - greater-than-or-equal-to (>=)
  - double-equals operator (==)
  - not-equals operator (!=)
  

- Logical operators:
  - And (&&)
  - Or (||)
  - Not (!)

- Short Circuiting: Where Go-Lang skips comparison calculations
  - It chains tests with logical operators for an outcome
  - If an Or (||) operate evaluates a test to be True, it stops the comparison there
  - If an And (&&) operate evaluates a test to be False, it stops the comparison there

- Equality & Floats: Better convert those floats because they don't play nice with comparisons!

func main() {
  ygoDetails := map[string]string {
    "Name": "Xie",
    "DeckName": "Manipulstring",
    "Dimension": "Xyz Dimension",
  }

  // Example #1
  if true {
    fmt.Println("The test is true!")
  }


  // Example #2
  if pop, ok := ygoDetails["Name"]; ok {
    fmt.Println(pop)
  }
  // Below line of code will cause an error because variables are block-scoped
  // fmt.Println(pop)
}

Looping

Loops:
- For statements: Simple l00ps:
  - for initializer; test; increment {}
    - for test {}
    - for {}
NOTE: The iteration variables in a loop are scoped to that block

- Exiting early:
  - break (breaks out of a loop entirely)
    - continue (skips an interation of a loop)
    - labels (Allows you to use break out from an outer loop)

- Looping over collections:
  - Arrays, slices, maps, strings, and channels can be looped through
    - NOTE: Channels are a special case
  - "for k, v := range collection {}" to get the key/value of an item in a collection
    - Use "_" (underscore) as a throwaway variable to get EITHER the key/value

// Example 1: Basic loop
func main() {
  for i := 0; i < 5; i++ {
    fmt.Println(i)
  }

  // You can also change the increment value
  for i := 0; i < 5; i = i+2 {
    fmt.Println(i)
  }

}

// Example 2: Having the initializer be outside the loop
// NOTE: You still need the first semi-colon when you do this
func main() {
  i := 0
  for ; i < 5; i++ {
    fmt.Println(i)
  }

// You can go further and put the incremental in the loop itself
// If you do, and you remove the initalizer too, you can remove the semi-colons completely
  i = 0
  for i < 10 {
    fmt.Println(i)
    i++
  }
}

// Example 3: Simplifying EVERYTHING
func main() {
  i = 0
  for {
    fmt.Println(i)
    i++
		
    // WARNING: Without this break checker, this loop will run forever
    if i == 5 {
      break
    }
  }
}

// Example 4: Continuing on
func main() {
  for i := 10; i < 20; i++ {
    if i%2 == 0 {
      continue
    }
  fmt.Println(i)
  }
}

// Example 5: LABEL IT
func main() {
Loop:
  for i := 1; i <= 3; i++ {
    for j := i; j <= 3; j++ {
      fmt.Println(i * j)
      if i * j >= 3 {
        break Loop
      }
    }
  }
}

Switches

- Initializers: Allows you to generate a statement to set-up for a comparison
 - Switching on a tag
 - Cases with multiple tests
   - There can be NO OVERLAP in testing cases
 - Switches with no tags
   - There CAN be overlap in testing cases
   - The first case that evaluates to True gets used if there is overlap

 - Fallthrough keyword
   - While most other languages have explicit breaks and implicit fallthrough,
   - Go has the reverse: Implicit breaks and explicit fallthroughs
   - Keep in mind that using fallthrough will execute anything below it, regardless of any calculations
- Type switches: To get the underlying types

// Example #1
func main() {
  switch 5 {
  case 1:
    fmt.Println("one")
  case 2:
    fmt.Println("two")
  default:
    fmt.Println("not one or two")
  }
}

// Example #2
func main() {
switch 5 {
  case 1, 5, 10:
    fmt.Println("one, five, or ten")
  case 2, 4, 6:
    fmt.Println("two, four, or six")
  default:
    fmt.Println("another number")
  }
}

// Example #3
func main() {
switch i := 2 + 4; i {
  case 1, 5, 10:
    fmt.Println("one, five, or ten")
  case 2, 4, 6:
    fmt.Println("two, four, or six")
  default:
    fmt.Println("another number")
  }
}

// Example #4: Tagless syntax
func main() {
  i := 10
  switch {
    case i <= 10:
    fmt.Println("less than or equal to ten")

    // Will force the below case to execute regardless of logic
    // fallthrough
  case i <= 20:
    fmt.Println("less than or equal to twenty")
  default:
    fmt.Println("greater than twenty")
  }
}

// Example #5: Type switching
func main() {
  var e interface{} = 1 // An int
  switch e.(type) {
    case int:
      fmt.Println("e is an int")
    case float64:
      fmt.Println("e is a float64")
    case string:
      fmt.Println("e is string")
    default:
      fmt.Println("e is another type")
  }
}


Defer, Panic, and Recover

Defer:
- Used to delay execution of a statement until function exits
- Useful to group "open" and "close" functions together
  - Be careful in loops
- Runs in LIFO (last-in, first-out) order
- Arguments evaluated at time defer is executed, NOT at time of called function is executed

Panic:
- Occurs when program cannot continue at all
  - Don't use when file can't be opened, unless it is critical
  - Use for unrecoverable events - I.E cannot obtain TCP port for web server
- Function will stop executing
  - Deferred functions will still fire
- If nothing handles panic, program will exit

Recover:
- Used to recover from panics
- Only useful in deferred functions
- Current function will not attempt to continue, but higher functions in call stack will


Pointers

Creating pointers:
- Pointer types use an asterisk (*) as a prefix to type pointers to
  - I.E *int - a point to an integer
- Use to addressof operator (&) to get the address of a variable

De-referencing pointers:
- De-reference a pointer by preceding with an asterisk (*)
- Complex types (I.E structs) are automatically de-referenced

Create pointers to objects:
- Can use the addressof operator (&) if value type already exists
  - ms := myStruct{foo: 42}
  - p := &ms
- Use addressof operator before initializer
  - &myStruct{foo: 42}
- Use new keyword
  - Can't initialize fields at the same time

Types with internal pointers:
- All assignment operations in Go are copy operations
- Slices and maps contain internal pointers, so copies point to same underlying data

d

By Levi

Leave a Reply

Your email address will not be published. Required fields are marked *