CMU 15-112: Fundamentals of Programming and Computer Science
Class Notes: Sequences in Go


  1. Strings
  2. Slices
  3. 2D Slices

  1. Strings
    package main import "fmt" func main() { s := "hello" // Strings are defined with double quotes c := 'c' // Characters (runes) are defined with single quotes fmt.Println(s) // prints "hello" fmt.Println(c) // prints ... 99? fmt.Println() /* Runes in Go are integers representing the ord of the character. To print the character itself we can cast it to a string */ fmt.Println(string(c)) }

    Looping over strings via index
    package main import "fmt" func main() { s := "Don't forget to be awesome" for i := 0; i < len(s); i += 1 { // Indexing into a string gives us a character fmt.Println(s[i], string(s[i])) } }

  2. Looping over strings with range
    package main import "fmt" func main() { /* We can loop over a range in Go just like in Python. The range gives us index, character pairs */ for index, character := range "hello" { fmt.Println(index, character, string(character)) } }

    Ignoring the index
    package main import "fmt" func main() { /* If we don't use the index but still name it, we get a compilation error. We can fix this by replacing the index variable name with an underscore */ //for _, character := range "hello" { for index, character := range "hello" { fmt.Println(string(character)) } }

    Slicing
    package main import "fmt" // Strings can be sliced [start:stop] just like in Python func main() { s := "Don't forget to be awesome" fmt.Println(s[16:]) fmt.Println(s[19:22], "inspiring") }

    Converting between runes and strings
    package main import "fmt" func main() { s := "a" // this is a string // We can get runes out of a string by looping over it for _, r := range s { fmt.Println(r) } // Or by indexing into it fmt.Println(s[0]) r := 'a' // this is a rune fmt.Println(string(r)) // which we can cast to a string }

    The strings module
    package main import ( "fmt" "strings" ) func main() { /* The strings module contains a variety of convenience methods for strings. See here for more: https://golang.org/pkg/strings/ */ s := "Don't forget to be awesome" fmt.Println(strings.Contains(s, "awesome")) fmt.Println(strings.Index(s, "be")) fmt.Println(strings.Count(s, " ")) }

  3. Slices
    package main import "fmt" func main() { /* In go, the closest structure to a Python list is called a slice. We can statically allocate a slice like this. Slices always have a defined type. You can read []int as "a slice of integers" */ a := []int{1, 2, 3, 4, 5} fmt.Println(a) }

    Creating slices with make
    package main import "fmt" func main() { /* This line makes an empty slice with 5 elements. By default the slice is filled with zeros */ a := make([]int, 5) fmt.Println(a) }

    Appending to slices
    package main import "fmt" func main() { a := make([]int, 0) // An empty slice // Append usually returns an alias, but sometimes returns a shallow copy a = append(a, 112) a = append(a, 42) fmt.Println(a) }

    Looping over slices by index
    package main import "fmt" func main() { a := []string{"a", "b", "c", "d"} for i := 0; i < len(a); i += 1 { fmt.Println(a[i]) } }

    Looping over slices with range
    package main import "fmt" func main() { a := []string{"carpe", "diem"} for _, word := range a { fmt.Println(word) } }

    Concatenating Slices
    package main import "fmt" /* In Go, there is no + operator between slices. Instead, we use the following synatx for adding slices */ func main() { a := []int{1,2,3} b := []int{4,5,6} c := append(a, b...) // Adds each element of b as an argument to append fmt.Println(c) }

    Slice Equality
    package main import ( "fmt" "github.com/CMU15-112/golang" ) /* Slices can't be compared directly with == in Go. Instead, use cs112.Equals */ func main() { fmt.Println(cs112.Equals([]int{1,2}, []int{1,2})) fmt.Println(cs112.Equals([]int{1,2}, []int{3,4})) }

    Utility Functions
    package main import ( "fmt" "github.com/CMU15-112/golang" ) /* cs112 exposes MaxSlice, MinSlice, Index, Count, and Contains functions on slices */ func main() { fmt.Println(cs112.MaxSlice([]int{8,7,6,9,8})) // 8 fmt.Println(cs112.MaxSlice([]string{"a", "b", "z"})) // "z" fmt.Println(cs112.MinSlice([]int{1,5,4,-3})) // -3 fmt.Println() fmt.Println(cs112.Index([]int{1,2,9,8}, 2)) // 1 fmt.Println(cs112.Index([]int{}, 42)) // -1 fmt.Println() fmt.Println(cs112.Count([]int{1,2,2,2,3,4,4,5}, 2)) // 3 fmt.Println() fmt.Println(cs112.Contains([]int{1,2,3}, 3)) // true fmt.Println(cs112.Contains([]string{"b", "c", "hello"}, "hello")) // true fmt.Println(cs112.Contains([][]int{{1,2}, {3,4}}, []int{3,4})) // true }

  4. 2D Slices
    package main import "fmt" func main() { /* We can statically allocate slices like this */ a := [][]int{ {1, 2, 3, 4}, {5, 6, 7, 8}, } /* You can read [][]int as "slice of integer slices" like a "list of lists of numbers" */ for row := 0; row < len(a); row += 1 { for col := 0; col < len(a[0]); col += 1 { fmt.Print(a[row][col], " ") } fmt.Println() } }

    Creating an empty 2d slice
    package main import "fmt" func main() { a := make([][]int, 5) fmt.Println(a) }

    Dynamically creating a 2d slice
    package main import "fmt" func make2dList(rows, cols int) [][]int { result := make([][]int, rows) // an empty 2d list of numbers for row := 0; row < rows; row += 1 { result[row] = make([]int, cols) } return result } func printGrid(grid [][]int) { for _, row := range grid { fmt.Println(row) } } func main() { n := 5 grid := make2dList(n, n) for i := 0; i < n; i += 1 { grid[i][i] = 1 } printGrid(grid) }