1
0
mirror of https://github.com/golang/go synced 2024-11-19 16:54:44 -07:00

reflect: allow Copy to a byte array or byte slice from a string

This somewhat mirrors the special case behavior of the copy built-in.

Fixes #22215

Change-Id: Ic353003ad3de659d3a6b4e9d97295b42510f3bf7
Reviewed-on: https://go-review.googlesource.com/70431
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Tim Cooper 2017-10-12 17:42:18 -03:00 committed by Ian Lance Taylor
parent c14dcfda6b
commit 245e386e4c
2 changed files with 58 additions and 4 deletions

View File

@ -668,6 +668,47 @@ func TestCopy(t *testing.T) {
}
}
func TestCopyString(t *testing.T) {
t.Run("Slice", func(t *testing.T) {
s := bytes.Repeat([]byte{'_'}, 8)
val := ValueOf(s)
n := Copy(val, ValueOf(""))
if expecting := []byte("________"); n != 0 || !bytes.Equal(s, expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 0, s = %s", n, s, expecting)
}
n = Copy(val, ValueOf("hello"))
if expecting := []byte("hello___"); n != 5 || !bytes.Equal(s, expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 5, s = %s", n, s, expecting)
}
n = Copy(val, ValueOf("helloworld"))
if expecting := []byte("hellowor"); n != 8 || !bytes.Equal(s, expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 8, s = %s", n, s, expecting)
}
})
t.Run("Array", func(t *testing.T) {
s := [...]byte{'_', '_', '_', '_', '_', '_', '_', '_'}
val := ValueOf(&s).Elem()
n := Copy(val, ValueOf(""))
if expecting := []byte("________"); n != 0 || !bytes.Equal(s[:], expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 0, s = %s", n, s[:], expecting)
}
n = Copy(val, ValueOf("hello"))
if expecting := []byte("hello___"); n != 5 || !bytes.Equal(s[:], expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 5, s = %s", n, s[:], expecting)
}
n = Copy(val, ValueOf("helloworld"))
if expecting := []byte("hellowor"); n != 8 || !bytes.Equal(s[:], expecting) {
t.Errorf("got n = %d, s = %s, expecting n = 8, s = %s", n, s[:], expecting)
}
})
}
func TestCopyArray(t *testing.T) {
a := [8]int{1, 2, 3, 4, 10, 9, 8, 7}
b := [11]int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}

View File

@ -1864,6 +1864,8 @@ func AppendSlice(s, t Value) Value {
// It returns the number of elements copied.
// Dst and src each must have kind Slice or Array, and
// dst and src must have the same element type.
//
// As a special case, src can have kind String if the element type of dst is kind Uint8.
func Copy(dst, src Value) int {
dk := dst.kind()
if dk != Array && dk != Slice {
@ -1875,14 +1877,20 @@ func Copy(dst, src Value) int {
dst.mustBeExported()
sk := src.kind()
var stringCopy bool
if sk != Array && sk != Slice {
panic(&ValueError{"reflect.Copy", sk})
stringCopy = sk == String && dst.typ.Elem().Kind() == Uint8
if !stringCopy {
panic(&ValueError{"reflect.Copy", sk})
}
}
src.mustBeExported()
de := dst.typ.Elem()
se := src.typ.Elem()
typesMustMatch("reflect.Copy", de, se)
if !stringCopy {
se := src.typ.Elem()
typesMustMatch("reflect.Copy", de, se)
}
var ds, ss sliceHeader
if dk == Array {
@ -1896,8 +1904,13 @@ func Copy(dst, src Value) int {
ss.Data = src.ptr
ss.Len = src.Len()
ss.Cap = ss.Len
} else {
} else if sk == Slice {
ss = *(*sliceHeader)(src.ptr)
} else {
sh := *(*stringHeader)(src.ptr)
ss.Data = sh.Data
ss.Len = sh.Len
ss.Cap = sh.Len
}
return typedslicecopy(de.common(), ds, ss)