Golang中make()创建的切片使用append时为何会基于长度值产生空条目

Golang中make()创建的切片使用append时为何会基于长度值产生空条目

str_slice := make([]string, 1)
str_slice = append(str_slice, "X")
str_slice = append(str_slice, "Y")
str_slice = append(str_slice, "Z")
for _, val := range str_slice {
	anyThing = append(anyThing, val)
}

fmt.Println(anyThing)

len(str_slice) 的值为 4。如果我们在 make() 中将长度参数设置为 0,就不会出现这个问题。

在进行追加操作时,难道不能自动检测到它是空的并放置在第一个位置吗?在最新的 Go 版本中,是否有任何提案来改变这种行为?


更多关于Golang中make()创建的切片使用append时为何会基于长度值产生空条目的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

感谢 @skillian

更多关于Golang中make()创建的切片使用append时为何会基于长度值产生空条目的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果我想在Go中尽可能接近地匹配你的Python代码,我会这样写:

listString := []string{}
listString = append(listString, "abc")
listString = append(listString, "xyz")
fmt.Println(listString)

str_slice := make([]string,1)

之后,该切片并非空:它有一个条目,其值为字符串的“零”值 ""。 如果你想要一个空切片,可以尝试

str_slice := make([]string, 0, 1)

listString = [] 在 Python 中不等同于 listString = make([]string, 1),而更像是 listString = make([]string, 0)

listString = make([]string, 1) 在 Go 中更类似于 Python 中的 listString = [""]

这与是否为编译型语言无关。

是的,有道理,这就是为什么我提到如果在 make() 中指定 len=0 会有所不同。 Go 会使用该类型的默认值进行初始化。(这与 C 语言不同) 我想指出的是,当执行 append 操作时,为什么它不能覆盖第一个 "" 条目,并将 X 作为其第一个条目。

这是因为它是编译型语言。初始化应该为这个切片创建一个默认值条目,其类型由它持有的数据类型决定。

来自Python背景的我曾这样想——这是在运行时动态发生的。

listString = []
listString.append("abc)
listString.append("xyz)
print(listString)

–> [“abc”, “xyz”]

有道理。这会产生运行时开销。

谢谢 @jonoke@NobbZ

因为该元素可能特意是 "",而且检查它是否为随机值会产生运行时开销,这是某些人不希望看到的。

如果你想根据你对“空”的定义来覆盖那些看似是空值的先前条目,你需要添加自己的追加函数。

// 代码示例:自定义追加函数
func appendIfNotEmpty(slice []string, element string) []string {
    if element != "" {
        return append(slice, element)
    }
    return slice
}

在Go语言中,make([]T, length, capacity)创建的切片会根据length参数进行初始化。当你使用make([]string, 1)时,会创建一个长度为1、容量为1的切片,其中第一个元素是string类型的零值(空字符串"")。

问题出现在这里:

str_slice := make([]string, 1)  // str_slice = [""]
str_slice = append(str_slice, "X")  // str_slice = ["", "X"]

append()函数总是在切片的末尾追加元素,而不是在"空"位置。它不会检测元素是否为零值,因为零值在Go中是有效的值。

正确的做法是:

// 方法1:创建长度为0的切片
str_slice := make([]string, 0)
str_slice = append(str_slice, "X")  // str_slice = ["X"]

// 方法2:使用字面量
str_slice := []string{"X"}

// 方法3:如果知道容量,可以指定容量但长度为0
str_slice := make([]string, 0, 10)  // 长度为0,容量为10
str_slice = append(str_slice, "X")

关于你的第二个问题:Go语言团队不会改变这种行为,因为:

  1. 零值是有效的值,区分"空"和"零值"会增加复杂性
  2. 当前行为明确且一致:append总是追加到末尾
  3. 这符合Go的设计哲学——简单和可预测

如果你需要覆盖第一个元素而不是追加,应该直接赋值:

str_slice := make([]string, 1)
str_slice[0] = "X"  // 直接赋值,而不是append

或者使用索引操作:

str_slice := make([]string, 3)
str_slice[0] = "X"
str_slice[1] = "Y"
str_slice[2] = "Z"
回到顶部