扩展切片的大小以防止切片边界超出范围错误

时间:2016-10-10 05:59:22

标签: go

我写了以下内容:

func main() {
    //inside main        
        fileInputBytes, err := ioutil.ReadFile("/tmp/test")
        byteSize2 := len(fileInputBytes)

        var inputFileByteSlice = fileInputBytes[0:]
        var numberOfIndexes = math.Floor(float64(byteSize / indexingOffset))

        for i := 1; i <= int(numberOfIndexes); i++ {
            // adding i to the indexer insures that we use lookahed to ignore previously inserted indexing values
            var v int = (i * indexingOffset) + i
            Insert(&inputFileByteSlice, v+i, indexingByteValue)
            fmt.Println(i)
        }
    }
    //outside main
    //variation of https://blog.golang.org/slices with pointers and such
        func Insert(slice *[]byte, index int, value byte) {
            // Grow the slice by one element.
            (*slice) = (*slice)[0 : len(*slice)+1]
            // Use copy to move the upper part of the slice out of the way and open a hole.
            copy((*slice)[index+1:], (*slice)[index:])
            // Store the new value.
            (*slice)[index] = value
            // Return the result.
        }

slice bounds out of range错误让我很紧张。切片的长度超出了大小并且溢出,我不明白的原因是我认为呼叫“成长”了。切片一个元素(复制前)将动态分配更多空间。既然情况并非如此,那么有人能给我一个更好的建议吗?

2 个答案:

答案 0 :(得分:1)

首先,切片已经是参考类型。因此,如果您不打算更改其容量,则无需传递其指针。因此,您的main可以简化为:

func main() {
    fileInputBytes, err := ioutil.ReadFile("/tmp/test")
    byteSize2 := len(fileInputBytes)

    // No need to use pointer to slice. If you want a brand new slice
    // that does not affect the original slice values, use copy()
    inputFileByteArray := fileInputBytes
    var numberOfIndexes = math.Floor(float64(byteSize / indexingOffset))

    for i := 1; i <= int(numberOfIndexes); i++ {
        var v int = (i * indexingOffset) + i

        // Insert needs to return the newly updated slice reference
        // which should be assigned in each iteration.
        inputFileByteArray = Insert(inputFileByteArray, v+i, indexingByteValue)
        fmt.Println(i)
    }
}

然后,只需使用Insertappend并返回新创建的切片,即可简化copy函数:

func Insert(slice []byte, index int, value byte) []byte {
    if index >= len(slice) {
        // add to the end of slice in case of index >= len(slice)
        return append(slice, value)
    }
    tmp := make([]byte, len(slice[:index + 1]))
    copy(tmp, slice[:index])
    tmp[index] = value
    return append(tmp, slice[index:]...)
}

这可能不是最好的实现,但它很简单。用法示例:https://play.golang.org/p/Nuq4RX9XQD

答案 1 :(得分:1)

只有切片恰好具有足够的初始容量时,您的功能才有效。如果您需要更多容量,您只能“成长”&#34;使用append函数的切片。您仍然可以使用*[]byte指针参数来修改切片,如下所示:

func Insert(slice *[]byte, index int, value byte) {
    *slice = append(*slice, 0)
    copy((*slice)[index+1:], (*slice)[index:])
    (*slice)[index] = value
}

但是,更常见的是返回新的切片值,并且每次都重新分配它。这为内置append提供了类似的函数签名。

func Insert(slice []byte, index int, value byte) []byte {
    slice = append(slice, 0)
    copy(slice[index+1:], slice[index:])
    slice[index] = value
    return slice
}