【问题标题】:when is it a good idea to reference a slice indice expression?什么时候引用切片索引表达式是个好主意?
【发布时间】:2020-11-29 19:27:49
【问题描述】:

在使用切片时,我很难找到一个创建对索引表达式的引用是个好主意的好案例。

因为切片,通过内置函数append,是使用特定机制实现的,它们的支持数组可以在运行时修改,虽然这被认为是一件好事,但我下面的代码有一个不明显的错误。

但在下面的例子中,从编译器的角度来看这是完全正确的,这对大多数程序员来说是非常混乱的,但是,这是语言规范允许的。

package main

import (
    "fmt"
)

func main() {
    broken()
    fmt.Printf("------------\n")
    lessbroken()
}
func broken() {
    var lump []int
    var lumpp []*int

    for i := 0; i < 8; i++ {
        lump = append(lump, int(i))
        lumpp = append(lumpp, &lump[i])
    }
    *(lumpp[0]) = 5
    fmt.Printf("lump[0]: %#v\n", lump[0])
}

func lessbroken() {
    lump := make([]int, 8, 8)
    var lumpp []*int

    for i := 0; i < 8; i++ {
        lump[i] = i
        lumpp = append(lumpp, &lump[i])
    }
    *(lumpp[0]) = 5
    fmt.Printf("lump[0]: %#v\n", lump[0])
}

输出

lump[0]: 0
------------
lump[0]: 5

https://play.golang.org/p/rl5O9ecp7Zq

我很难理解Why does pointer assignment cause variable assignment to not always stick? 的帖子,现在我想弄清楚我是否应该将其视为不好的做法,或者是否有什么东西,我可能想念..

【问题讨论】:

  • “因为切片大多由运行时自动管理,所以它们的内存地址可以在运行时修改” 前件和后件都是错误的:切片都不是“由运行时管理”(至少不会更多)比 Go 中的任何其他变量)也不能它们的“地址......被修改”(因为没有变量的地址可以被修改)。在切片增长期间,一个 new 切片(可能会返回一个新地址和一个新的后备数组,但旧切片及其地址不变。
  • 好的,精度是值得的。不过,当您说切片不以某种方式由运行时管理时,我仍然不相信。
  • 这就像说int32变量由运行时管理。是的,它们在运行时为变量和 GC 提供内存的意义上说,它曾经无法访问,但因此它是非信息,因为对于 Go 中的所有内容都是如此:int32、complex126、chan uint8 和函数闭包命名为很少。切片并不比布尔更“由运行时管理”。
  • 我认为罪魁祸首在If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.。参考:golang.org/ref/spec#Appending_and_copying_slices 我说明的造成困难的“东西”是append 内置函数。但是append 是使用切片的方式,并且与这种类型密切相关。为了初步解决这个问题,我说没关系......
  • ...用slice这个词来概括。

标签: go


【解决方案1】:

您必须小心存储指向切片元素的指针,因为切片是数组的视图,而您真正存储的是指向底层数组元素的指针。即使数组仍然有效,切片也可以在添加元素时分配一个新数组。

处理这个问题的常用方法是首先使用指针切片。这样,即使切片可以分配一个新数组,数组元素指向的实际数据仍然有效,并且可以毫无问题地取消引用。

解决这个问题的另一种方法是预先分配切片,或者先填充切片,然后在没有更多附加操作剩余时处理指向其元素的指针。这就是您在示例的第二部分中已经展示的内容。

这是否是不好的做法取决于具体情况。如果以后有可能其他人会来修改逻辑,我认为第一种选择更安全。

【讨论】:

  • 完全同意这个帖子,尤其是A common way to deal with this problem is to use a slice of pointers in the first place.
  • 出于好奇,这篇文章出了什么问题(这就是那个问题)stackoverflow.com/questions/65095052/…?有什么想法吗?
  • 我想你是在问你的答案?我看不出你的回答有什么问题。
  • 是的,我对接受的答案和我得到的许多反对票感到困惑,我不在乎反对票,这对我来说没有意义,我想知道我是否遗漏了一些明显的东西,但是有没有额外的 cmets 来解释这些反对票。因此我的问题在这里。感谢您确认这只是系统故障。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
相关资源
最近更新 更多