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 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号