Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Experiments With Go Arrays and Slices from Blog Posts - SQLServerCentral

Save for later
  • 5 min read
  • 30 Dec 2020

article-image

Simplicity Over Syntactic Sugar

As I’ve been learning Go, I’ve grown to learn that many decisions to simplify the language have removed many features that provide more succinct expressions in languages such as Python, PowerShell, C#, and others.

The non-orthogonal features in the languages result in many expressive ways something can be done, but at a cost, according to Go’s paradigm.

My background is also heavily focused in relational databases and set based work, so I’m realizing as I study more programming paradigms seperate from any database involvement, that it’s a fundamental difference in the way a database developer and a normal developer writing backend code look at this.

Rather than declarative based syntax, you need to focus a lot more on iterating through collections and manipulating these.

As I explored my assumptions, I found that even in .NET Linq expressions are abstracting the same basic concept of loops and iterations away for simpler syntax, but not fundamentally doing true set selections.

In fact, in some cases I’ve read that Linq performance is often worse than a simple loop (see this interesting stack overflow answer)

The catch to this is that the Linq expression might be more maintainable in an enterprise environment at the cost of some degraded performance (excluding some scenarios like deferred execution).

For example, in PowerShell, you can work with arrays in a multitude of ways.

$array[4..10] | ForEach-Object {}
# or
foreach($item in $array[$start..$end]){}

This syntactic sugar provides brevity, but as two ways among many I can think of this does add such a variety of ways and performance considerations.

Go strips this cognitive load away by giving only a few ways to do the same thing.

Using For Loop

This example is just int slices, but I’m trying to understand the options as I range through a struct as well.

When working through these examples for this question, I discovered thanks to the Rubber Duck debugging, that you can simplify slice selection using newSlice := arr[2:5].

Simple Loop

As an example: Goplay Link To Run

package main
import "fmt"
func main() {
startIndex := 2
itemsToSelect := 3
arr := []int{10, 15, 20, 25, 35, 45, 50}
fmt.Printf("starting: arr: %vn", arr)
newCollection := []int{}
fmt.Printf("initialized newCollection: %vn", newCollection)
for i := 0; i < itemsToSelect; i++ {
newCollection = append(newCollection, arr[i+startIndex])
fmt.Printf("tnewCollection: %vn", newCollection)
}
fmt.Printf("= newCollection: %vn", newCollection)
fmt.Print("expected: 20, 25, 35n")
}```

This would result in:

```text
starting: arr: [10 15 20 25 35 45 50]
initialized newCollection: []
newCollection: [20]
newCollection: [20 25]
newCollection: [20 25 35]
= newCollection: [20 25 35]
expected: 20, 25, 35

Moving Loop to a Function

Assuming there are no more effective selection libraries in Go, I’m assuming I’d write functions for this behavior such as Goplay Link To Run.

package main
import "fmt"
func main() {
startIndex := 2
itemsToSelect := 3
arr := []int{10, 15, 20, 25, 35, 45, 50}
fmt.Printf("starting: arr: %vn", arr)
newCollection := GetSubselection(arr, startIndex, itemsToSelect)
fmt.Printf("GetSubselection returned: %vn", newCollection)
fmt.Print("expected: 20, 25, 35n")
}
func GetSubselection(arr []int, startIndex int, itemsToSelect int) (newSlice []int) {
fmt.Printf("newSlice: %vn", newSlice)
for i := 0; i < itemsToSelect; i++ {
newSlice = append(newSlice, arr[i+startIndex])
fmt.Printf("tnewSlice: %vn", newSlice)
}
fmt.Printf("= newSlice: %vn", newSlice)
return newSlice
}

which results in:

starting: arr: [10 15 20 25 35 45 50]
newSlice: []
newSlice: [20]
newSlice: [20 25]
newSlice: [20 25 35]
= newSlice: [20 25 35]
GetSubselection returned: [20 25 35]
expected: 20, 25, 35

Trimming this down further I found I could use the slice syntax (assuming the consecutive range of values) such as:

Goplay Link To Run

func GetSubselection(arr []int, startIndex int, itemsToSelect int) (newSlice []int) {
fmt.Printf("newSlice: %vn", newSlice)
newSlice = arr[startIndex:(startIndex + itemsToSelect)]
fmt.Printf("tnewSlice: %vn", newSlice)
fmt.Printf("= newSlice: %vn", newSlice)
return newSlice
}

Range

The range expression gives you both the index and value, and it works for maps and structs as well.

Turns outs you can also work with a subselection of a slice in the range expression.

package main
import "fmt"
func main() {
startIndex := 2
itemsToSelect := 3
arr := []int{10, 15, 20, 25, 35, 45, 50}
fmt.Printf("starting: arr: %vn", arr)
fmt.Printf("Use range to iterate through arr[%d:(%d + %d)]n", startIndex, startIndex, itemsToSelect)
for i, v := range arr[startIndexexperiments-with-go-arrays-and-slices-from-blog-posts-sqlservercentral-img-0startIndex + itemsToSelect)] {
fmt.Printf("ti: %d v: %dn", i, v)
}
fmt.Print("expected: 20, 25, 35n")
}

Slices

While the language is simple, understanding some behaviors with slices caught me off-guard.

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime

First, I needed to clarify my language.

Since I was looking to have a subset of an array, slices were the correct choice.

For a fixed set with no changes, a standard array would be used.

Tour On Go says it well with:

An array has a fixed size.

A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array.

In practice, slices are much more common than arrays.

For instance, I tried to think of what I would do to scale performance on a larger array, so I used a pointer to my int array.

However, I was using a slice.

This means that using a pointer wasn’t valid.

This is because whenever I pass the slice it is a pass by reference already, unlike many of the other types.

newCollection := GetSubSelection(&arr,2,3)
func GetSubSelection(arr *[]int){ ...

I think some of these behaviors aren’t quite intuitive to a new Gopher, but writing them out helped clarify the behavior a little more.

Resources

This is a bit of a rambling about what I learned so I could solidify some of these discoveries by writing them down. #learninpublic

For some great examples, look at some examples in:

If you have any insights, feel free to drop a comment here (it’s just a GitHub powered comment system, no new account required).

#powershell #tech #golang #development

The post Experiments With Go Arrays and Slices appeared first on SQLServerCentral.