mirror of
https://github.com/golang/go
synced 2024-11-18 04:14:49 -07:00
reflect: allow conversion from slice to array
Updates #46505 Change-Id: Ib8f52d6ae199338f278731267c966da85dd0acdd Reviewed-on: https://go-review.googlesource.com/c/go/+/430475 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
36760ca9fd
commit
805f174e5c
@ -4323,6 +4323,25 @@ var convertTests = []struct {
|
||||
{V(MyString("runes♝")), V(MyRunes("runes♝"))},
|
||||
{V(MyRunes("runes♕")), V(MyString("runes♕"))},
|
||||
|
||||
// slice to array
|
||||
{V([]byte(nil)), V([0]byte{})},
|
||||
{V([]byte{}), V([0]byte{})},
|
||||
{V([]byte{1}), V([1]byte{1})},
|
||||
{V([]byte{1, 2}), V([2]byte{1, 2})},
|
||||
{V([]byte{1, 2, 3}), V([3]byte{1, 2, 3})},
|
||||
{V(MyBytes([]byte(nil))), V([0]byte{})},
|
||||
{V(MyBytes{}), V([0]byte{})},
|
||||
{V(MyBytes{1}), V([1]byte{1})},
|
||||
{V(MyBytes{1, 2}), V([2]byte{1, 2})},
|
||||
{V(MyBytes{1, 2, 3}), V([3]byte{1, 2, 3})},
|
||||
{V([]byte(nil)), V(MyBytesArray0{})},
|
||||
{V([]byte{}), V(MyBytesArray0([0]byte{}))},
|
||||
{V([]byte{1, 2, 3, 4}), V(MyBytesArray([4]byte{1, 2, 3, 4}))},
|
||||
{V(MyBytes{}), V(MyBytesArray0([0]byte{}))},
|
||||
{V(MyBytes{5, 6, 7, 8}), V(MyBytesArray([4]byte{5, 6, 7, 8}))},
|
||||
{V([]MyByte{}), V([0]MyByte{})},
|
||||
{V([]MyByte{1, 2}), V([2]MyByte{1, 2})},
|
||||
|
||||
// slice to array pointer
|
||||
{V([]byte(nil)), V((*[0]byte)(nil))},
|
||||
{V([]byte{}), V(new([0]byte))},
|
||||
@ -4399,6 +4418,8 @@ var convertTests = []struct {
|
||||
// cannot convert mismatched array sizes
|
||||
{V([2]byte{}), V([2]byte{})},
|
||||
{V([3]byte{}), V([3]byte{})},
|
||||
{V(MyBytesArray0{}), V([0]byte{})},
|
||||
{V([0]byte{}), V(MyBytesArray0{})},
|
||||
|
||||
// cannot convert other instances
|
||||
{V((**byte)(nil)), V((**byte)(nil))},
|
||||
@ -4574,6 +4595,34 @@ func TestConvertPanic(t *testing.T) {
|
||||
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
|
||||
_ = v.Convert(pt)
|
||||
})
|
||||
|
||||
if v.CanConvert(pt.Elem()) {
|
||||
t.Errorf("slice with length 4 should not be convertible to [8]byte")
|
||||
}
|
||||
shouldPanic("reflect: cannot convert slice with length 4 to array with length 8", func() {
|
||||
_ = v.Convert(pt.Elem())
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvertSlice2Array(t *testing.T) {
|
||||
s := make([]int, 4)
|
||||
p := [4]int{}
|
||||
pt := TypeOf(p)
|
||||
ov := ValueOf(s)
|
||||
v := ov.Convert(pt)
|
||||
// Converting a slice to non-empty array needs to return
|
||||
// a non-addressable copy of the original memory.
|
||||
if v.CanAddr() {
|
||||
t.Fatalf("convert slice to non-empty array returns a addressable copy array")
|
||||
}
|
||||
for i := range s {
|
||||
ov.Index(i).Set(ValueOf(i + 1))
|
||||
}
|
||||
for i := range s {
|
||||
if v.Index(i).Int() != 0 {
|
||||
t.Fatalf("slice (%v) mutation visible in converted result (%v)", ov, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var gFloat32 float32
|
||||
|
@ -3245,10 +3245,14 @@ func (v Value) CanConvert(t Type) bool {
|
||||
if !vt.ConvertibleTo(t) {
|
||||
return false
|
||||
}
|
||||
// Currently the only conversion that is OK in terms of type
|
||||
// but that can panic depending on the value is converting
|
||||
// from slice to pointer-to-array.
|
||||
if vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array {
|
||||
// Converting from slice to array or to pointer-to-array can panic
|
||||
// depending on the value.
|
||||
switch {
|
||||
case vt.Kind() == Slice && t.Kind() == Array:
|
||||
if t.Len() > v.Len() {
|
||||
return false
|
||||
}
|
||||
case vt.Kind() == Slice && t.Kind() == Pointer && t.Elem().Kind() == Array:
|
||||
n := t.Elem().Len()
|
||||
if n > v.Len() {
|
||||
return false
|
||||
@ -3401,6 +3405,11 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
|
||||
if dst.Kind() == Pointer && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() {
|
||||
return cvtSliceArrayPtr
|
||||
}
|
||||
// "x is a slice, T is a array type,
|
||||
// and the slice and array types have identical element types."
|
||||
if dst.Kind() == Array && src.Elem() == dst.Elem() {
|
||||
return cvtSliceArray
|
||||
}
|
||||
|
||||
case Chan:
|
||||
if dst.Kind() == Chan && specialChannelAssignability(dst, src) {
|
||||
@ -3604,6 +3613,22 @@ func cvtSliceArrayPtr(v Value, t Type) Value {
|
||||
return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Pointer)}
|
||||
}
|
||||
|
||||
// convertOp: []T -> [N]T
|
||||
func cvtSliceArray(v Value, t Type) Value {
|
||||
n := t.Len()
|
||||
if n > v.Len() {
|
||||
panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to array with length " + itoa.Itoa(n))
|
||||
}
|
||||
h := (*unsafeheader.Slice)(v.ptr)
|
||||
typ := t.common()
|
||||
ptr := h.Data
|
||||
c := unsafe_New(typ)
|
||||
typedmemmove(typ, c, ptr)
|
||||
ptr = c
|
||||
|
||||
return Value{typ, ptr, v.flag&^(flagAddr|flagKindMask) | flag(Array)}
|
||||
}
|
||||
|
||||
// convertOp: direct copy
|
||||
func cvtDirect(v Value, typ Type) Value {
|
||||
f := v.flag
|
||||
|
Loading…
Reference in New Issue
Block a user