Welcome to this course on Revisiting Go Basics, part of the Fundamental Coding Interview Preparation in Go course path!
Before delving into Go programming for interview preparation, let's explore some foundational concepts in Go. We'll focus on Go's slices and examine how strings are handled. These tools are crucial for organizing multiple elements, such as numbers or letters, within a single structure.
Go's slices are dynamically-sized, flexible views into the elements of an array. Unlike arrays, slices are dynamic and allow you to change their contents, providing significant flexibility. Let’s see how to create and modify slices:
Go1package main 2 3import "fmt" 4 5func main() { 6 // Defining a slice 7 mySlice := []int{1, 2, 3, 4} 8 9 // Printing the first (0-indexed) element of the slice 10 fmt.Println(mySlice[0]) 11 12 // Changing the first element of the slice 13 mySlice[0] = 100 14 15 // Now, mySlice contains {100, 2, 3, 4} 16 fmt.Println(mySlice) 17}
In this simple snippet:
- We define
mySlice
as a slice of integers, containing the elements1, 2, 3, 4
. - We access the first element via indexing using
mySlice[0]
- We update the first element by assigning a new value
mySlice[0] = 100
Slices in Go serve as a powerful abstraction over arrays. They allow you to efficiently manage collections of data, providing several built-in functions for manipulation. These operations include appending elements, slicing, and removing elements.
append()
is a function that adds a new element to the end of a slice, effectively increasing its size. To remove elements, you can employ slicing techniques; for example, mySlice[1:]
selects all elements of mySlice
starting from index 1
, effectively removing the element at index 0
.
For many other operations, such as finding an element in a slice, the idiomatic way in Go to carry out such operations is to simply employ for loops. The example below illustrates these operations:
Go1package main 2 3import "fmt" 4 5 6func main() { 7 // Creating a slice 8 fruits := []string{"apple", "banana", "cherry"} 9 10 // Adding a new element using append 11 fruits = append(fruits, "date") 12 13 // Inserting an element by manual slicing 14 fruits = append(fruits[:1], append([]string{"bilberry"}, fruits[1:]...)...) 15 16 // Finding the position of 'banana' and removing it 17 for i, fruit := range fruits { 18 if fruit == "banana" { 19 fruits = append(fruits[:i], fruits[i+1:]...) 20 break 21 } 22 } 23 24 // Accessing elements using indexing 25 firstFruit := fruits[0] // "apple" 26 lastFruit := fruits[len(fruits)-1] // "date" 27 28 // Now, fruits equals {"apple", "bilberry", "cherry", "date"} 29 fmt.Println(fruits) 30 fmt.Println(firstFruit, lastFruit) 31}
Here, append()
adds "date" to the end of the fruits
slice. Manual slicing is utilized to insert "bilberry", and a loop helps locate and remove "banana". The slicing operation for inserting "bilberry" involves breaking the slice and reconstructing it with the new element. The three dots (...)
notation in fruits[1:]...
is called the "variadic argument" expansion. It allows you to pass elements of fruits[1:]
as separate arguments to the append()
function, effectively appending each element individually.
In Go, strings are sequences of bytes, typically representing UTF-8 encoded text. Strings are immutable, which means once created, their contents cannot be changed. However, you can manipulate them with package functions like strings.ToLower
, strings.ToUpper
, strings.Split
, strings.Trim
, or strings.Replace
. We'll discuss some of these functions in more detail in a later unit, but for now let's see a couple of basic operations in action:
Go1package main 2 3import ( 4 "fmt" 5 "strings" 6) 7 8func main() { 9 // Creating a string 10 greeting := "HeLLo, WoRlD!" 11 12 // Accessing characters using indexing 13 firstChar := greeting[0] // 'H' 14 lastChar := greeting[len(greeting)-1] // '!' 15 16 // Lowercasing the entire string 17 lowerGreeting := strings.ToLower(greeting) 18 // greeting becomes "hello, world!" 19 20 // Convert the string back to uppercase 21 upperGreeting := strings.ToUpper(greeting) 22 // greeting becomes "HELLO, WORLD!" 23 24 fmt.Printf("%c %c\n", firstChar, lastChar) 25 fmt.Println(lowerGreeting) 26 fmt.Println(upperGreeting) 27}
In this example, we use indexing to access the first and last characters in a string. To print them as characters, we utilize fmt.Printf
with the %c
verb to convert their byte values to characters. Additionally, we showcase strings.ToLower
and strings.ToUpper
functions, which convert the string to lowercase and uppercase, respectively.
In Go, both slices and strings use zero-based indexing for element access. This forms the basis for various useful operations, such as slicing, concatenation, and finding elements.
-
Slicing: This operation allows you to extract a portion of a slice or string using straightforward syntax:
slice[start:end]
. Note that, similarly to many other languages, thestart
index is inclusive but theend
index is not. -
Concatenation: Use
append()
for slices and the+
operator for strings to join elements. -
Finding elements: Search for elements in a slice using loops, or use the
strings
package for string-specific operations.
Go1package main 2 3import ( 4 "fmt" 5 "sort" 6 "strings" 7) 8 9func main() { 10 // Define a slice and a string 11 mySlice := []int{1, 2, 3, 4, 5} 12 greeting := "Hello" 13 14 // Slicing: get elements within a range 15 slicePart := mySlice[2:4] // Extract elements from index 2 to 3 16 sliceString := greeting[1:3] // Retrieves 'el' 17 18 // Concatenation: join slices and strings 19 concatenateSlice := append(mySlice, 6, 7, 8) 20 concatenateString := greeting + ", world!" 21 22 // Finding and counting occurrences 23 count := 0 24 for _, v := range mySlice { 25 if v == 2 { 26 count++ 27 } 28 } 29 countL := strings.Count(greeting, "l") 30 31 // Sorting items in a slice 32 sort.Sort(sort.Reverse(sort.IntSlice(mySlice))) // Sorts in descending order 33 34 fmt.Println(slicePart) 35 fmt.Println(sliceString) 36 fmt.Println(concatenateSlice) 37 fmt.Println(concatenateString) 38 fmt.Println(count, countL) 39 fmt.Println(mySlice) 40}
Here, append()
concatenates slices, and strings.Count
finds occurrences of a substring in a string. The sort
package is also used to sort elements in mySlice
in descending order.
Excellent work! You've now explored the basic structure of Go's slices and strings, learning how to create, access, and manipulate these data structures using various operations.
Next, solidify your understanding through hands-on practice with Go-specific exercises. Grasping these concepts and frequent practice will equip you to tackle more complex problem-solving tasks effortlessly. Happy coding!