英文:
How to initialize slice with initial values and capacity at the same time?
问题
一些代码如下所示:
const ESTIMATEDSIZE = 10000
var init_arr = [...]int{1,1,2,3,5,8,13}
var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE)
}
在Go语言中,没有像C++中的vector
那样可以为切片fibbo
预留ESTIMATEDSIZE
的函数,以减少在扩展容量时的复制时间。因此,我只能在初始化时将ESTIMATEDSIZE
赋值给容量。但是以下两种方式都是不合法的:
var fibbo []int = init_arr[::ESTIMATEDSIZE]
var fibbo []int = make([]int{1,1,2,3,5,8,13}, len(init_arr), ESTIMATEDSIZE)
有没有办法解决这个问题?或者下面这个笨拙的代码是唯一的方法吗?
var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE)
for i:= range init_arr {
fibbo[i] = init_arr[i]
}
英文:
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]
}
答案1
得分: 4
在一行中初始化切片的长度和容量,
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]
在一行中初始化切片的长度和容量,
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]
英文:
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]
答案2
得分: 2
你可以用两行代码完成,减少了对专用函数的需求:
fibbo := make([]int, len(init_arr), ESTIMATEDSIZE)
copy(fibbo, init_arr)
Go语言中切片(slice)和C++中的向量(vector)之间的关键区别在于,向量拥有其元素,而切片是对底层缓冲区的视图。对向量的操作会改变其接收器,而对切片的操作会返回一个新的切片。
// C++
v.push_back(1); // 现在其他地方也会看到v有一个额外的元素
// Go
u := append(v, 1) // 其他地方仍然看到v的原始长度,而创建了一个具有额外元素的新切片u
因此,你需要在向量上使用`reserve`方法,因为创建一个新的向量不会影响接收器,这不是Go切片的要求,所以不需要专门的reserve函数。
```cpp
// C++
v.reserve(100); // 其他地方需要看到具有额外容量的v,这不能通过创建另一个向量u来实现
// Go
u := reserve(v) // 其他地方看不到具有额外容量的v,只有u可以看到
英文:
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
答案3
得分: -3
不,这是不可能的。这是Go设计哲学的一部分,它决定了这个设计决策:“不要隐藏复杂性”。
你的“笨拙”代码实际上是在Go中完成这个任务的首选和惯用方式,只需要做一个小改动:
var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE)
for i := range init_arr {
fibbo[i] = init_arr[i]
}
(除了格式化之外),我唯一做的改动是从var
声明中删除了类型,因为那是完全多余的。换句话说:
-var fibbo []int = make([]int, len(init_arr), ESTIMATEDSIZE)
+var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE)
正如评论中指出的,如果你不对输入进行其他修改,你还可以使用内置的copy
函数来消除for循环:
var fibbo = make([]int, len(init_arr), ESTIMATEDSIZE)
copy(fibbo, init_arr)
英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论