Slice index greater than length and less than capacity gives error - go

Following code gives a error at runtime.
package main
import fmt "fmt"
func main(){
type b []int
var k = make([]b, 5, 10)
fmt.Printf("%d\n",k[8])
fmt.Printf("%d", len(k))
}
Error is as follows.
panic: runtime error: index out of range
runtime.panic+0x9e /go/src/pkg/runtime/proc.c:1060
runtime.panic(0x453b00, 0x300203f0)
runtime.panicstring+0x94 /go/src/pkg/runtime/runtime.c:116
runtime.panicstring(0x4af6c6, 0xc)
runtime.panicindex+0x26 /go/src/pkg/runtime/runtime.c:73
runtime.panicindex()
main.main+0x8d C:/GOEXCE~1/basics/DATATY~1/slice.go:9
main.main()
runtime.mainstart+0xf 386/asm.s:93
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:178
runtime.goexit()
----- goroutine created by -----
_rt0_386+0xbf 386/asm.s:80
While if k[0] or k[1] is printed, it runs fine. Can you please explain what exactly capacity means for slices.

You are simply indexing, so the index must be less than the length. The relevant section of the Go specification says that
A primary expression of the form
a[x]
...
For a of type A or *A where A is an array type, or for a of type S
where S is a slice type:
x must be an integer value and 0 <= x < len(a)
However, if you were "slicing" (e.g. a[6:9]), then it would work with indexes that are greater than the length but within the capacity.

Read the Go Programming Language Specification.
Length and capacity
The capacity of a slice is the number of elements for which there is
space allocated in the underlying array. At any time the following
relationship holds:
0 <= len(s) <= cap(s)

var slice = make([]b, 5, 10)
is equal to
var array [10]b
slice := array[:5]
The difference is that when you use var slice = make([]b, 5, 10), you can't access the array under slice. The slice := array[:5] means the first element of slice is array[0] and the length of slice is 5, which means slice[0] == array[0], slice[1] == array[1], ... slice[4] == array[4]. Because you can only access the index that is less than the length(which means 0 <= index < length). The length of slice is 5 and the length of array is 10, so you can access array[8](0<=8<10) but can't access slice[8](8>5).
Full sample:
package main
import fmt "fmt"
func main(){
type b []int
var array [10]b
slice := array[:5]
// []
fmt.Printf("%d\n",slice[1])
// []
fmt.Printf("%d\n",array[8])
// panic: runtime error: index out of range
fmt.Printf("%d\n",slice[8])
}
Reference
https://blog.golang.org/go-slices-usage-and-internals

Related

Why is ID after the assignment in the loop 0?

I am trying to create a array of struct and initiate some data in it.
The struct:
type Person struct{
id int
enlighten bool
channel chan int
}
The assignments:
table := make([]Philospher, numPhil)
for i :=0; i < 5; i++{
p := Philospher{
id: i,
enlighten: false,
channel: make(chan int),
}
table = append(table, p)
}
for j :=0; j < 5; j++{
fmt.Println(table[j].id);
}
The following are the output of above code:
0
0
0
0
0
I am trying to figure out why it is not
0
1
2
3
4
I have also tried to use add & in front of Philospher, and it is the same thing
Any help is appreciated
Your make call is creating a Philosopher slice with the initial length of 5. From the spec:
A new, initialized slice value for a given element type T is made using the built-in function make, which takes a slice type and parameters specifying the length and optionally the capacity. A slice created with make always allocates a new, hidden array to which the returned slice value refers. That is, executing
make([]T, length, capacity)
Those first 5 Philosophers are the zero value of Philosopher. You append 5 more Philosophers to the end of the slice which gives it a final length of 10. What I believe you meant to do is create a slice with the length of 0 but a capacity of 5:
table := make([]Philosopher, 0, numPhil)
https://play.golang.org/p/a5QP6wd6Rs_9
Because of this:
table := make([]Philospher, numPhil)
This creates table with numPhil empty elements. Then you add your Philosohpers to the end of this empty table, and print of the first 5. Apparently, numPhil >= 5, so it prints out the first empty ones.
Change the initialization to:
table:= make([]Philosopher,0,numPhil)
to reserve space for numPhil elements, with a size of 0.

How to create a 2D array based on the length passed to an array

func matrix(n int) {
var result [n][n]int //Does not work
fmt.Println(result)
}
How to create a 2D array based on the length passed to an array; n is the length of the array.
The Go Programming Language Specification
Array types
An array is a numbered sequence of elements of a single type, called
the element type. The number of elements is called the length and is
never negative.
ArrayType = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int. The length
of array a can be discovered using the built-in function len. The
elements can be addressed by integer indices 0 through len(a)-1. Array
types are always one-dimensional but may be composed to form
multi-dimensional types.
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int.
The size of an array is fixed at compile-time.
Use a slice instead.
For example,
package main
import "fmt"
func matrix(n int) [][]int {
m := make([][]int, n)
for i := range m {
m[i] = make([]int, n)
}
return m
}
func main() {
fmt.Println(matrix(3))
}
Playground: https://play.golang.org/p/D1MHmm5KCht
Output:
[[0 0 0] [0 0 0] [0 0 0]]
You have to allocate the further dimensions individually, like so:
func matrix(n int) {
var result = make([][]int, n)
for i := range result {
result[i] = make([]int, n)
}
fmt.Println(result)
}
With an actual array with fixed dimensions known at compile-time, you can do something like:
var result [5][5]int
but this is not the case you have.

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)

Flipping a slice with a for loop logic error

So I am trying to write a method that takes two slices, flips both of them and then gives them to each other.
Ex.
s1 = {1,2,3,4,5}
s2 = {6,7,8,9,10}
Should return:
s1 = {10,9,8,7,6}
s2 = {5,4,3,2,1}
Here is my code:
package main
import(
"fmt"
)
func main(){
f:= [5]int{1,2,3,4,5}
h:= [5]int{6,7,8,9,10}
var sliceF []int = f[0:5]
var sliceH []int = h[0:5]
fmt.Println(reverseReverse(sliceF,sliceH))
}
func reverseReverse(first []int, second []int) ([]int, []int){
//creating temp arrays to hold the traversed arrays before swapping.
var tempArr1 []int = first
var tempArr2 []int = second
//count is used for counting up the tempArrays in the correct order in the For loops
var count int= 0
//goes through the first array and sets the values starting from the end equal to the temp array
//which increases normally from left to right.
for i :=len(first)-1; i>=0;i--{
tempArr1[count] = first[i]
fmt.Println(i)
count++
}
count =0
//same as first for loop just on the second array
for i :=len(second)-1; i>=0;i--{
tempArr2[count] = second[i]
count++
}
//trying to replace the values of the param arrays to be equal to the temp arrays
first=tempArr2
second = tempArr1
//returning the arrays
return first,second
}
When run here is the output:
4
3
2
1
0
[10 9 8 9 10]
[5 4 3 4 5]
*Not I included a print statement in the for loop to check if the index is decreasing properly.
I understand there are better ways to do this but for proof of concept I want to use a for loop.
Any help appreciated. I am new to go and tend to have java habits so I assume somehow my problem is related to that.
This can be done much simpler by realizing there's no need to actually swap the individual elements. Instead, reverse each array and swap their order. Much simpler!
func reverseReverse( a, b []int ) ([]int, []int) {
return reverse(b), reverse(a)
}
func reverse( a []int ) []int {
end := len(a) - 1
// Allocate a new array slice of the same length to copy to.
ret := make( []int, len(a) )
// Copy each element of a into ret, reversed.
for i := range a {
ret[end-i] = a[i]
}
return ret
}
With that revelation, there's little need for the very specialized reverseReverse function. Swap the order yourself.
fmt.Println(reverse(sliceH), reverse(sliceF))
Note that if you just want to take a slice of an array, it's sufficient to write sliceH []int := h[:] without specifying the start and end. The start is assumed to be 0 and the end is the end. Also note there's no need to declare the type, := takes care of that for you.
Even better, you can declare and initialize them directly.
sliceF:= []int{1,2,3,4,5}
sliceH:= []int{6,7,8,9,10}
Short answer:
tempArr1[count] = first[i]
This line is logically identical to:
first[count] = first[i]
Detailed answer:
x := [5]int{} and x := []int{} are in fact two very different assignments. In the first case x is actually a static array. In the second case x is a slice which is in fact a data structure which has a length, capacity and a pointer to the underlying array. Therefore, var tempArr1 []int = first means copy the pointer to the underlying array of first into the tempArr1, so any modification to first[i] will be reflected in tempArr1 and vice versa
For example,
package main
import "fmt"
func reverse(s []int) []int {
for i := 0; i < len(s)/2; i++ {
s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
}
return s
}
func main() {
s1, s2 := []int{1, 2, 3, 4, 5}, []int{6, 7, 8, 9, 10}
fmt.Println(s1, s2)
s1, s2 = reverse(s2), reverse(s1)
fmt.Println(s1, s2)
}
Output:
[1 2 3 4 5] [6 7 8 9 10]
[10 9 8 7 6] [5 4 3 2 1]

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.

Resources