Golang中切片长度改变但容量不变的解决方案

Golang中切片长度改变但容量不变的解决方案 我想问一个问题。有没有这样的函数:切片长度改变但容量不变?因为我不想重新分配内存,这会带来开销。

例如: 切片长度=5,切片容量=10;调整大小后切片长度=0,切片容量=10。

6 回复

你的代码确实将长度设为0而保持容量不变。但我不确定这是否会带来时间开销和内存重新分配。期待你的回答。

更多关于Golang中切片长度改变但容量不变的解决方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


它创建了一个新的切片,但这仅占用12字节(在64位机器上),同时复用了底层数组。

我相当确定,这会在先前填充的切片或后续子切片上创建一个"写时复制"的切片。

在追加操作时,是否正确定义了哪个切片会被重新分配?或者这是未定义行为?

只需创建一个包含零个元素的新切片

package main

import (
	"fmt"
)

func main() {
	// 原始切片
	s := []int{1, 2, 3, 4, 5}
	fmt.Printf("原始切片: %v\n", s)
	fmt.Printf("原始切片地址: %p\n", &s[0])

	// 创建零长度切片(共享相同底层数组)
	empty := s[:0]
	fmt.Printf("零长度切片: %v\n", empty)
	fmt.Printf("零长度切片地址: %p\n", &s[0])
}

在这个示例中,您可以看到底层数组的地址保持不变。

也许这个例子能说明问题:https://play.golang.org/p/fGwnKN70dmk

在这个示例中,ab 是两个指向同一数组的切片,这就是为什么向 b 追加元素后,打印 a 时能看到变化的原因…

编辑:我刚刚完整阅读了关于重新分配的问题。从这个其他示例来看,似乎并没有发生重新分配,内部只是修改了 lenhttps://play.golang.org/p/xGlzY2xd2Lg。但 Johan 和 Norbert 提到确实会发生,所以我需要再仔细研究一下。

进一步编辑:在这篇文章中提到,切片操作不会复制切片的数据。它会创建一个指向原始数组的新切片值。但Effective Go中提到:只要切片仍然在底层数组的限制范围内,就可以更改其长度;只需将其分配给自身的切片即可。在我看来,我们遇到的情况属于后者。

在Go语言中,可以通过重新切片(reslicing)来改变切片的长度而不改变其容量,从而避免重新分配内存。这通过调整切片的起始和结束索引实现。

以下是一个示例代码:

package main

import "fmt"

func main() {
    // 创建一个初始切片,长度为5,容量为10
    slice := make([]int, 5, 10)
    fmt.Printf("初始状态: 长度=%d, 容量=%d\n", len(slice), cap(slice))

    // 通过重新切片将长度设为0,容量保持不变
    slice = slice[:0]
    fmt.Printf("调整后: 长度=%d, 容量=%d\n", len(slice), cap(slice))

    // 验证容量未变,可以重新使用底层数组
    slice = append(slice, 1, 2, 3)
    fmt.Printf("追加元素后: 长度=%d, 容量=%d, 内容=%v\n", len(slice), cap(slice), slice)
}

输出结果:

初始状态: 长度=5, 容量=10
调整后: 长度=0, 容量=10
追加元素后: 长度=3, 容量=10, 内容=[1 2 3]

在这个例子中,通过 slice = slice[:0] 将切片长度重置为0,而容量保持为10不变。这利用了切片底层数组的现有空间,避免了内存重新分配。后续可以使用 append 函数向切片添加新元素,直到长度超过容量才会触发重新分配。

回到顶部