douhuijun3776 2014-05-29 00:51
浏览 32
已采纳

复制切片有什么意义?

What is the point of this snippet of code:

t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
for i := range s {
    t[i] = s[i]
}
s = t

It's from this page: http://blog.golang.org/go-slices-usage-and-internals, and is supposed to grow a slice. However, above that code snippet is a diagram which depicts a slice as a struct with a pointer, a length, and a capacity. Why does each individual entry have to be copied over instead of something like:

t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
t = s[:]
s = t

And if the problem is that the capacity of t is changed to be the same as s, why isn't there another way of setting the pointers to be the same. Or does a slice have a pointer to every single element in the array within its bounds?

Edit: I read a little further and got to this snippet of code:

func CopyDigits(filename string) []byte {
    b, _ := ioutil.ReadFile(filename)
    b = digitRegexp.Find(b)
    c := make([]byte, len(b))
    copy(c, b)
    return c
}

Its purpose is to stop referencing the file after c is returned by using copy. Does this imply that copy copies the underlying array as well as the slice?

  • 写回答

1条回答 默认 最新

  • dtjw6660 2014-05-29 01:03
    关注

    To construct a new, higher capacity underlying array with the same length and values as the old underlying array. The old underlying array will be reclaimed by the garbage collector. For example,

    package main
    
    import "fmt"
    
    func main() {
        s := []byte{0, 1, 2, 3, 4}[:3]
        fmt.Printf("s: %p %d %v %d %v
    ", &s[0], len(s), s, cap(s), s[:cap(s)])
        t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
        fmt.Printf("t: %p %d %v %d %v
    ", &t[0], len(t), t, cap(t), t[:cap(t)])
        for i := range s {
            t[i] = s[i]
        }
        s = t
        fmt.Printf("s: %p %d %v %d %v
    ", &s[0], len(s), s, cap(s), s[:cap(s)])
        fmt.Printf("t: %p %d %v %d %v
    ", &t[0], len(t), t, cap(t), t[:cap(t)])
    }
    

    Output:

    s: 0x10500168 3 [0 1 2] 5 [0 1 2 3 4]
    t: 0x1052e130 3 [0 0 0] 12 [0 0 0 0 0 0 0 0 0 0 0 0]
    s: 0x1052e130 3 [0 1 2] 12 [0 1 2 0 0 0 0 0 0 0 0 0]
    t: 0x1052e130 3 [0 1 2] 12 [0 1 2 0 0 0 0 0 0 0 0 0]
    

    The Go Programming Language Specification

    Appending to and copying slices

    The function copy copies slice elements from a source src to a destination dst and returns the number of elements copied. Both arguments must have identical element type T and must be assignable to a slice of type []T. The number of elements copied is the minimum of len(src) and len(dst).

    Examples:

    var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    var s = make([]int, 6)
    var b = make([]byte, 5)
    n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
    n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
    n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
    

    If we return a reference to b, we pin the whole underlying array for b. Since b refers to a file, that could easily be megabytes or gigabytes. By returning a new underlying array c, which is the exact size of the number, a few bytes, there will no longer be a reference to the large underlying array for b and it will be reclaimed by the garbage collector. The copy built-in function copies values from b to c. For example,

    package main
    
    import "fmt"
    
    func Copy() []byte {
        b := []byte{0, 1, 2, 3, 4, 5, 6, 7}
        fmt.Printf("b: %p %d %v %d %v
    ", &b[0], len(b), b, cap(b), b[:cap(b)])
        b = b[:2]
        fmt.Printf("b: %p %d %v %d %v
    ", &b[0], len(b), b, cap(b), b[:cap(b)])
        c := make([]byte, len(b))
        copy(c, b)
        fmt.Printf("c: %p %d %v %d %v
    ", &c[0], len(c), c, cap(c), c[:cap(c)])
        return c
    }
    
    func main() {
        d := Copy()
        fmt.Printf("d: %p %d %v %d %v
    ", &d[0], len(d), d, cap(d), d[:cap(d)])
    }
    

    Output:

    b: 0x10500168 8 [0 1 2 3 4 5 6 7] 8 [0 1 2 3 4 5 6 7]
    b: 0x10500168 2 [0 1] 8 [0 1 2 3 4 5 6 7]
    c: 0x10500178 2 [0 1] 2 [0 1]
    d: 0x10500178 2 [0 1] 2 [0 1]
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类