Notes

  • This primarily started as notes for the “Slice Tricks In Go” doc, but figured it may actually prove more useful as a general “go cheat sheet” that captures all the little workarounds, quick one liners, etc. that come with using Go
  • Appending a slice to another slice (sees)

    • variadic arguments: (the ... syntax) packs arguments that you pass into a function into one slice (and vice versa when calling that function)
    • examples
      • a = append(a, b...) appends slice b to slice a
      • alternatively you can do a = append(a, 1, 2 ,3) to append it element by element

Copying an array

a := []int{1,2,3}
b := make([]int, len(a))
copy(b,a) // builtin copy(dst, src []Type)```
 

Delete (and Shift)

a = append(a[:i], a[i+1:]...) 
// append elements before i (exclusive) to i+1 (until end)
// probably only do this for non-structs or pointers because it can cause potential memory problems

Reverse elements

for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
	a[left], a[right] = a[right], a[left]
}
  • explanation: for left and right indices that start at opposite ends of the slice, swap elements until the pointers cross

Shuffle elements

import “math/rand”

// func Shuffle(n int, swap func(i, j int))
// uses the default pseudo-random range to swap elements
 
rand.Shuffle(len(a), func(i,j int) {
    a[i], a[j] = a[j], a[i]
})

Sliding Window

revisit after I’ve reviewed this pattern in grokking the coding interview

func slidingWindow(size int, input []int) [][]int {
   // returns the input slice as the first element
   if len(input) <= size {
   	return [][]int{input}
   }
 
   // allocate slice at the precise size we need
   r := make([][]int, 0, len(input)-size+1)
 
   for i, j := 0, size; j <= len(input); i, j = i+1, j+1 {
   	r = append(r, input[i:j])
   }
 
   return r
}

Sets in Go

  • Go doesn’t have sets as a built-in type or a contains function on slices/arrays for that matter. So it’s nice to keep in mind that the “Go way of doing things” here is to make the type you want as a map:
set := map[T]bool{...}
// technically you could also map to an empty struct
// which is somewhat more memory efficient, but I think 
// it kills readability and just isn't worth the dust of memory
 
// checking something is in the set is still fast ...
if set[x] {
  // do stuff
}
 
// alternatively the longer normal-map way of doing things
if val, ok := set[x]; ok {
  // do stuff here again
}```
Source: [contains method for a slice in go](https://stackoverflow.com/questions/10485743/contains-method-for-a-slice)
 
 ### Type Assertions & Type Casting
 - There's a subtle different and I think it's actually important to know the difference both to avoid getting tripped up AND because demonstrating that I understand the difference (and when to use one over the other) could look good during interviews
 - {{[[todo]]}} need to expand on this a little more and write up a good example to better understand this stuff
 
 - Source: [Trying to convert interface to int](https://stackoverflow.com/questions/18041334/convert-interface-to-int), [Go Conversions](https://go.dev/ref/spec#Conversions), [Go Type Assertions](https://go.dev/ref/spec#Type_assertions)
 
### Strings, Bytes, Runes and Characters In Go
 - A string holds arbitrary bytes -- it's not required to hold Unicode or UTF-8 encoded text. A string == a slice of bytes. 
    - The post also talks about some nuances that comes with trying to print strings (since they can just be bytes) but skipping over that for the most part
 - Side note on how you can write a string literal like `const placeOfInterest = ''`
    - **Go source code is UTF-8**, so the source code for the string literal is UTF-8 text. If that string literal contains no escape sequences, which a raw string cannot, the constructed string will hold exactly the source text between the quotes. 
    - So by definition and by construction the raw string will always contain a valid UTF-8 representation of its contents.
 - Re: what's expanded on in [[the absolute minimum every software developer should know about character sets (no excuses)]], the notion of a "character" in computing ambiguous, if we think of bytes (or a set of bytes) as containers that correspond to their Unicode symbol (i.e. code points), then it becomes a little clearer why we can't just say 1 byte == 1 character
 - Go introduces the concept of a **rune **to basically map to a code point i.e. an `int32`
 - Using a `for range` loop actually iterates through a UTF-8 string rune-by-rune, while a standard for loop, would actually iterate one byte at a time.
    - English alphabets can't tell the difference, but it's important if we do anything beyond those characters (nowadays emojis are a great example of how this is useful)
 - Sources: https://go.dev/blog/strings, [[the absolute minimum every software developer should know about character sets (no excuses)]]