How to initialize slice with initial values and capacity at the same time?

163 views Asked by At

some code is as follow:

const ESTIMATEDSIZE = 10000
var init_arr = [...]int{1,1,2,3,5,8,13}
var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE)    
}

There is no reserved function like vector in c++ for slice fibbo to reserve ESTIMATEDSIZE for a slice to reduce the copy time on extending capacity. So I can only assign ESTIMATEDSIZE to capacity at initialization. But neither of below is legal.

var fibbo []int = init_arr[::ESTIMATEDSIZE]
var fibbo []int = make([]int{1,1,2,3,5,8,13}, len(init_arr), ESTIMATEDSIZE)

Are there any method to this question? Or may be the clumsy code as follow is the only way?

var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE) 
for i:= range init_arr {
    fibbo[i] = init_arr[i]
}
3

There are 3 answers

1
Jonathan Hall On BEST ANSWER

No, this cannot be done. And it's part of the Go design philosophy that informs this design decision: "Don't hide complexity."

Your "clumsy" code is actually the preferred and idiomatic way to do this in Go, with one minor change:

var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE) 
for i := range init_arr {
    fibbo[i] = init_arr[i]
}

(Other than formatting), the only change I made was to remove the type from the var declaration, since that's entirely superflous. In other words:

-var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE) 
+var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE) 

As pointed out in comments, you can also use the copy built-in to eliminate the for loop, if you're not doing any other alterations on the inputs:

var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE)
copy(fibbo, init_arr)
0
rocka2q On

Initialize slice length and capacity in one line,

package main

import "fmt"

const capFibs = 93

func main() {
    fibs := []int{1, 1, 2, 3, 5, 8, 13, (capFibs - 1): 0}[:7]
    fmt.Println(len(fibs), cap(fibs), fibs)
}

https://go.dev/play/p/IbSBkpFuhw6

7 93 [1 1 2 3 5 8 13]

Initialize slice length and capacity in one line,

package main

import "fmt"

const capFibs = 93

func main() {
    fibs := append(make([]int, 0, capFibs), []int{1, 1, 2, 3, 5, 8, 13}...)
    fmt.Println(len(fibs), cap(fibs), fibs)
}

https://go.dev/play/p/lUxH6GtdM-K

7 93 [1 1 2 3 5 8 13]
0
Quân Anh Mai On

You can do it in 2 lines, which limits the need for a dedicated function:

fibbo := make([]int, len(init_arr), ESTIMATEDSIZE)
copy(fibbo, init_arr)

The key difference between a slice in Go and a vector in C++ is that a vector owns its elements, while a slice is a view over the underlying buffer. An operation on a vector changes its receiver, while an operation on a slice returns a new one.

// C++
v.push_back(1); // Now other places will also see that v has an additional element
// Go
u := append(v, 1) // Other places still see v with its original length, a new slice u is created with an additional element instead

As a result, you need a reserve method on vector because creating a new one will not affect the receiver, this is not a requirement of Go slice, so a dedicated reserve function is not needed.

// C++
v.reserve(100); // Other places need to see v with additional capacity, this cannot be obtained by creating another vector u
// Go
u := reserve(v) // Other places does not see v with additional capacity, only u does