mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
reflect: add Value.CanConvert
For #395 For #46746 Change-Id: I4bfc094cf1cecd27ce48e31f92384cf470f371a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/334669 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
parent
9e26569293
commit
48c88f1b1b
@ -80,6 +80,7 @@ pkg net/url, method (Values) Has(string) bool
|
|||||||
pkg reflect, func VisibleFields(Type) []StructField
|
pkg reflect, func VisibleFields(Type) []StructField
|
||||||
pkg reflect, method (Method) IsExported() bool
|
pkg reflect, method (Method) IsExported() bool
|
||||||
pkg reflect, method (StructField) IsExported() bool
|
pkg reflect, method (StructField) IsExported() bool
|
||||||
|
pkg reflect, method (Value) CanConvert(Type) bool
|
||||||
pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
|
pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
|
||||||
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
|
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
|
||||||
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}
|
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}
|
||||||
|
@ -989,6 +989,18 @@ func Foo() bool {
|
|||||||
|
|
||||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
<p><!-- CL 334669 -->
|
||||||
|
The new
|
||||||
|
<a href="/pkg/reflect/#Value.CanConvert"><code>Value.CanConvert</code></a>
|
||||||
|
method reports whether a value can be converted to a type.
|
||||||
|
This may be used to avoid a panic when converting a slice to an
|
||||||
|
array pointer type if the slice is too short.
|
||||||
|
Previously it was sufficient to use
|
||||||
|
<a href="/pkg/reflect/#Type.ConvertibleTo"><code>Type.ConvertibleTo</code></a>
|
||||||
|
for this, but the newly permitted conversion from slice to array
|
||||||
|
pointer type can panic even if the types are convertible.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p><!-- CL 266197 -->
|
<p><!-- CL 266197 -->
|
||||||
The new
|
The new
|
||||||
<a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>
|
<a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>
|
||||||
|
@ -4304,6 +4304,9 @@ func TestConvert(t *testing.T) {
|
|||||||
|
|
||||||
// vout1 represents the in value converted to the in type.
|
// vout1 represents the in value converted to the in type.
|
||||||
v1 := tt.in
|
v1 := tt.in
|
||||||
|
if !v1.CanConvert(t1) {
|
||||||
|
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t1)
|
||||||
|
}
|
||||||
vout1 := v1.Convert(t1)
|
vout1 := v1.Convert(t1)
|
||||||
out1 := vout1.Interface()
|
out1 := vout1.Interface()
|
||||||
if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) {
|
if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) {
|
||||||
@ -4311,6 +4314,9 @@ func TestConvert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// vout2 represents the in value converted to the out type.
|
// vout2 represents the in value converted to the out type.
|
||||||
|
if !v1.CanConvert(t2) {
|
||||||
|
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t2)
|
||||||
|
}
|
||||||
vout2 := v1.Convert(t2)
|
vout2 := v1.Convert(t2)
|
||||||
out2 := vout2.Interface()
|
out2 := vout2.Interface()
|
||||||
if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) {
|
if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) {
|
||||||
@ -4371,6 +4377,9 @@ func TestConvertPanic(t *testing.T) {
|
|||||||
if !v.Type().ConvertibleTo(pt) {
|
if !v.Type().ConvertibleTo(pt) {
|
||||||
t.Errorf("[]byte should be convertible to *[8]byte")
|
t.Errorf("[]byte should be convertible to *[8]byte")
|
||||||
}
|
}
|
||||||
|
if v.CanConvert(pt) {
|
||||||
|
t.Errorf("slice with length 4 should not be convertible to *[8]byte")
|
||||||
|
}
|
||||||
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
|
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
|
||||||
_ = v.Convert(pt)
|
_ = v.Convert(pt)
|
||||||
})
|
})
|
||||||
|
@ -2811,6 +2811,26 @@ func (v Value) Convert(t Type) Value {
|
|||||||
return op(v, t)
|
return op(v, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanConvert reports whether the value v can be converted to type t.
|
||||||
|
// If v.CanConvert(t) returns true then v.Convert(t) will not panic.
|
||||||
|
func (v Value) CanConvert(t Type) bool {
|
||||||
|
vt := v.Type()
|
||||||
|
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() == Ptr && t.Elem().Kind() == Array {
|
||||||
|
n := t.Elem().Len()
|
||||||
|
h := (*unsafeheader.Slice)(v.ptr)
|
||||||
|
if n > h.Len {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// convertOp returns the function to convert a value of type src
|
// convertOp returns the function to convert a value of type src
|
||||||
// to a value of type dst. If the conversion is illegal, convertOp returns nil.
|
// to a value of type dst. If the conversion is illegal, convertOp returns nil.
|
||||||
func convertOp(dst, src *rtype) func(Value, Type) Value {
|
func convertOp(dst, src *rtype) func(Value, Type) Value {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user