How should I define an empty slice in Go? - go

Or more precisely, it seems like I could do any of these three things. Is there any difference between them? Which is the best and why?
var foo []int
foo := []int{}
foo := make([]int, 0)

The difference is:
(1) is a nil slice (foo == nil).
(2) and (3) are non-nil slices (foo != nil).
The following points are true for all three statements:
The statement does not allocate memory.
The slice length is zero: len(foo) == 0.
The slice capacity is zero: cap(foo) == 0.
Playground example
Because len, cap and append work with nil slices, (1) can often be used interchangeably with (2) and (3).
Statements 2 and 3 are short variable declarations. These statements can also be written as a variable declaration with an initializer.
var foo = []int{}
var foo = make([]int, 0)
All of the options are used commonly in Go code.

Related

Adding/subtracting two numeric strings

I have two variables with big numbers set as strings:
var numA = "340282366920938463463374607431768211456"
var numB = "17014118346046923173168730371588410572"
I want to be able to add and subtract these kinds of large string numbers in Go.
I know I need to use math/big but I still can not for the life of me figure out how, so any example help will be greatly appreciated!
You may use big.NewInt() to create a new big.Int value initialized with an int64 value. It returns you a pointer (*big.Int). Alternatively you could simply use the builtin new() function to allocate a big.Int value which will be 0 like this: new(big.Int), or since big.Int is a struct type, a simple composite literal would also do: &big.Int{}.
Once you have a value, you may use Int.SetString() to parse and set a number given as string. You can pass the base of the string number, and it also returns you a bool value indicating if parsing succeeded.
Then you may use Int.Add() and Int.Sub() to calculate the sum and difference of 2 big.Int numbers. Note that Add() and Sub() write the result into the receiver whose method you call, so if you need the numbers (operands) unchanged, use another big.Int value to calculate and store the result.
See this example:
numA := "340282366920938463463374607431768211456"
numB := "17014118346046923173168730371588410572"
ba, bb := big.NewInt(0), big.NewInt(0)
if _, ok := ba.SetString(numA, 10); !ok {
panic("invalid numA")
}
if _, ok := bb.SetString(numB, 10); !ok {
panic("invalid numB")
}
sum := big.NewInt(0).Add(ba, bb)
fmt.Println("a + b =", sum)
diff := big.NewInt(0).Sub(ba, bb)
fmt.Println("a - b =", diff)
Output (try it on the Go Playground):
a + b = 357296485266985386636543337803356622028
a - b = 323268248574891540290205877060179800884

Slice out of bounds using [][]int but works with map[int][]int

Why does this code work
graph := make(map[int][]int, 0)
graph[0] = append(graph[0], 1)
But if you replace first line with graph := make([][]int, 0) I get panic: runtime error: index out of range? It's very weird.
Lets simplify your code, to make it more obvious what's happening (Playground link):
graph1 := make(map[int]int, 0)
graph2 := make([]int, 0)
x := graph1[0] // Success
y := graph2[0] // Panic
From this we see that the difference is due to map[int] vs []int -- the second array in your type is actually irrelevant.
Now to understand why this is happening, we need to understand how Go handles map and slice access. From Go Maps in Action we learn:
If the requested key doesn't exist, we get the value type's zero value.
In your original code, the zero value for a slice ([]int), is nil, and append() treats nil as the first argument as an empty slice.
But when we try to access the 0th element of an empty slice, we get a panic, because the slice is empty.
In summary, append and the second slice of your type are both red herrings in your question. The panic happens when trying to access the non-existent element in the first dimension of your slice.
When you do make in graph := make(map[int][]int, 0), you are allocating memory to your map, not to array. So you might do this only
graph := make(map[int][]int).
Decomping you code:
type a []int
type m map[int]a
func main() {
fmt.Println("Hello, playground")
//decomping graph := make(map[int][]int, 0)
graph := make(m)
//map is empty
fmt.Println(len(graph))
//decomping graph[0] := append(graph[0], 1)
itm_a := 1
arr_a := []int{}
//appeding item to "a" type
arr_a = append(arr_a, itm_a)
//appending array of a to graph
graph[0] = arr_a
//print graph
fmt.Println(graph)
}
See in playground.
The error that you are getting is caused for conceptual error.
When you does graph := make([][]int, 0), you are allocation memory to a slice of slice, not an array. See in https://blog.golang.org/go-slices-usage-and-internals.
So you can does this (decomping solution):
type a []int
type m []a
func main() {
fmt.Println("Hello, playground")
//decomping graph := make([][]int, 0)
//see that you must be set the length
graph := make(m, 0)
//map is empty
fmt.Println(len(graph))
//this is incorrect: graph[0] := append(graph[0], 1)
//this is correct: graph[0] := append(graph[0], []int{1})
//see:
itm_a := 1
arr_a := []int{}
//appeding item to "a" type
arr_a = append(arr_a, itm_a)
//appending slice of a to graph (slice)
graph = append(graph, arr_a)
//print graph
fmt.Println(graph)
}
See in playground
The code panics due to slice length being 0. If you want to append anything to the slice, you just have to provide its length as below.
graph := make([][]int, 1)
fmt.Println(len(graph))
graph[0] = append(graph[0], 1)
fmt.Println(graph)
To append data to a slice at first level, append to its first index and then append to second level just like below.
graph := make([][]int, 0)
fmt.Println(len(graph))
graph = append(graph, []int{1})
Check Playground example
make(map[int][]int, 0) creates a map of []int.
By design in Go you can get any element from a map. And if it doesn't exist you receive the "zero" value which here is an empty slice.
graph := make(map[int][]int)
graph[4] = append(graph[4], 1)
graph[7] = append([]int{}, 1, 2)
graph[11] = append([]int{1, 2, 3}, 4, 5)
printing it gives this slice:
fmt.Printf("%#v\n", graph)
map[int][]int{
4:[]int{1},
7:[]int{1, 2},
11:[]int{1, 2, 3, 4, 5},
}
Your second example create an empty slice of []int slices. Slices work differently from maps, so indexing an element that doesn't exist will give you a panic.

How to assign a value to the empty slice after the declaration

I am trying to assign a value to the empty slice as follows.
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
s[0] = 99
}
And it throws an exception,
panic: runtime error: index out of range
Note:
I know one way of doing this by initializing the value at declaration part as follows. But in the above example I am trying to assign a value after the declaration.
var s []int{99}
Is there a way to achieve this?
Empty slices cannot just be assigned to. Your print statement shows that the slice has length and capacity of 0. Indexing at [0] is definitely out of bounds.
You have (at least) three choices:
Append to the slice: s = append(s, 99)
or Initialize the slice to be non-empty: s := make([]int, 1)
or Initialize your slice with the element you want: s := []int{99}
You can find tutorials on slices in the Go tour, or a lot more details about slice usage and internals.
var s []int{99}
The above works but if you want to assign after declaration, then you would need to create a slice using make function with enough length
s := make([]int, 10)
s[0] = 10
fmt.Println(s)
This will initialize slice and set the length to 10 and its elements to zero values
Note: doing s[10] or any greater index will panic since the slice is initialised with length 10. If you want to dynamically increase the slice size, then use append
You can do that by using append function.
func main() {
var s []int
s = append(s,99)
fmt.Println(s) // [99]
}
https://play.golang.org/p/XATvSo2OB6f
// slice declaration; no memory allocation
var slice []int
//slice initialization with length (0) and capacity (10);
//memory allocated for 10 ints
slice = make([]int, 0, 10)
// push to the slice value - than increase length
slice = append(slice, 1)
//change the value. Index has to be lower then length of slice
slice[0] = 2
Take a loot at this output - https://play.golang.com/p/U426b1I5zRq
Of course, you can skip initialization with make, append will do it for you with default value of capacity (2). But for performance it is better to allocate memory only once (if you know how many elements are going to be added to the slice)

The zero value of a slice is not nil

I was following the example https://tour.golang.org/moretypes/10
I modified the code expecting to get the same result. I did not. Is this a bug, or a documentation error? The tour states
A nil slice has a length and capacity of 0.
My y variable has a length and capacity of 0.
package main
import "fmt"
func myPrint(z []int) {
fmt.Println(z, len(z), cap(z))
if z == nil {
fmt.Println("nil!")
}
}
func main() {
var z []int
y := []int {}
myPrint(z)
myPrint(y)
}
Here is my output.
[] 0 0
nil!
[] 0 0
I was expecting a second "nil"~ Why didn't I get it?
nil Vs empty slice
If we think of a slice like this:
[pointer] [length] [capacity]
then:
nil slice: [nil][0][0]
empty slice: [addr][0][0] // it points to an address
From: "Go in action" book:
nil slice
They’re useful when you want to represent a slice that doesn’t exist, such as when an exception occurs in a function that returns a slice.
// Create a nil slice of integers.
var slice []int
empty slice
Empty slices are useful when you want to represent an empty collection, such as when a database query returns zero results.
// Use make to create an empty slice of integers.
slice := make([]int, 0)
// Use a slice literal to create an empty slice of integers.
slice := []int{}
👉 Regardless of whether you’re using a nil slice or an empty slice, the built-in functions append, len, and cap work the same.
Go playground example:
package main
import (
"fmt"
)
func main() {
var nil_slice []int
var empty_slice = []int{}
fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))
}
prints:
true 0 0
false 0 0
The doc you referenced states that a nil slice has a length and capacity of 0, but not that every slice of length and capacity of zero is a nil slice. The specification only says that the value of an uninitialized slice is nil.
This is a convenience to support len and cap on slices which are uninitialised (nil). Otherwise we would need to check for non-nil first in order to avoid panic. (This also holds for other in-built types like maps or channels.)
In terms of the fmt.Print output, the difference in behaviour is similar to printing an uninitialised (nil) pointer vs pointer to an empty structure:
var s *struct{} // uninitialised pointer
fmt.Println(s) // <nil>
s = &struct{}{} // pointer to an empty structure
fmt.Println(s) // &{}
In this case:
var z []int
You have declared a variable z but you did not initialize it.
In this case:
y := []int {}
You declared it and initialized it, you set it to an empty slice. Writing the second expression the long way makes the difference between the two expressions more clear:
var y []int = []int {}
Your y variable isn't the zero value for a slice. It's allocated via an empty slice literal.
// both of these allocate a slice
y := []int{}
z := []int{1, 2, 3}
A nil slice has a length and capacity of 0 and has no underlying array.
var s []string => no underlying array
var s = []string => create a underlying array but his length is 0.

Declare slice or make slice?

In Go, what is the difference between var s []int and s := make([]int, 0)?
I find that both works, but which one is better?
Simple declaration
var s []int
does not allocate memory and s points to nil, while
s := make([]int, 0)
allocates memory and s points to memory to a slice with 0 elements.
Usually, the first one is more idiomatic if you don't know the exact size of your use case.
In addition to fabriziom's answer, you can see more examples at "Go Slices: usage and internals", where a use for []int is mentioned:
Since the zero value of a slice (nil) acts like a zero-length slice, you can declare a slice variable and then append to it in a loop:
// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
var p []int // == nil
for _, v := range s {
if fn(v) {
p = append(p, v)
}
}
return p
}
It means that, to append to a slice, you don't have to allocate memory first: the nil slice p int[] is enough as a slice to add to.
Just found a difference. If you use
var list []MyObjects
and then you encode the output as JSON, you get null.
list := make([]MyObjects, 0)
results in [] as expected.
A bit more complete example (one more argument in .make()):
slice := make([]int, 2, 5)
fmt.Printf("length: %d - capacity %d - content: %d", len(slice), cap(slice), slice)
Out:
length: 2 - capacity 5 - content: [0 0]
Or with a dynamic type of slice:
slice := make([]interface{}, 2, 5)
fmt.Printf("length: %d - capacity %d - content: %d", len(slice), cap(slice), slice)
Out:
length: 2 - capacity 5 - content: [<nil> <nil>]

Resources