string - 将字符串 slice 转换为指向字符串的指针 slice

标签 string pointers for-loop go memory

我想将一段字符串转换成一段指向字符串的指针

values1 := []string{"a", "b", "c"}
var values2 []*string
for _, v := range values1 {
    fmt.Printf("%p | %T\n", v, v)
    values2 = append(values2, &v)
}
fmt.Println(values2)

%!p(string=a) => string
%!p(string=b) => string
%!p(string=c) => string
[0xc42000e1d0 0xc42000e1d0 0xc42000e1d0]

据我了解,
我的变量 v 似乎是一个字符串,而不是指向字符串的指针。
因此 v 应该在迭代时从 values1 复制。

显然我错了,因为 v 仍然有相同的地址 0xc42000e1d0
如果不是指针,v 值如何改变?

要获得快速解决方案,请使用:

values1 := []string{"a", "b", "c"}
var values2 []*string
for i, _ := range values1 {
    values2 = append(values2, &values1[i])
}

最佳答案

第一个版本不起作用,因为只有一个循环变量 v,它在每次迭代中都有相同的地址。循环变量在每次迭代中分配,这会改变它的值而不是它的地址,并且您在每次迭代中附加这个相同的地址。

一个可能的解决方案是您提出的:附加原始 slice 的正确 slice 元素的地址:

for i := range values1 {
    values2 = append(values2, &values1[i])
}

这可行,但请注意 values2 包含指向 values1 的后备数组的地址,因此 values1 的后备数组将被保留在内存中(不会被垃圾收集),直到 values1values2 变量都无法访问。另请注意,修改 values1 的元素将间接影响 values2,因为 values2 的元素指向 values1 的元素。

另一种解决方案是创建临时局部变量并附加这些变量的地址:

for _, v := range values1 {
    v2 := v
    values2 = append(values2, &v2)
}

通过这样做,您的 values2 slice 将不会阻止 values1 被垃圾收集,而且修改 values1 中的值也不会反射(reflect)在values2,它们将是独立的。

查看循环变量的相关问题:

Why do these two for loop variations give me different behavior?

Golang: Register multiple routes using range for loop slices/map

关于string - 将字符串 slice 转换为指向字符串的指针 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48459846/

相关文章:

c++ - for循环如何在不打印的情况下工作

Javascript 移除所有空的 innerHTML 子元素

javascript - push() 一个二维数组

Java 类型转换。 (String)、.toString() 和 ""+ int 背后的逻辑

c - 下面的输出如何可能?

java - 检查一个字符串是否包含另一个字符串的字符的最快方法是什么?

c++ - 通过传递引用或返回它来初始化结构是更好的风格吗?

C++通过函数初始化类指针

c# - 识别字符串中字符/数字/特殊字符的数量

java - 按照模板将 long 转换为字符串