mirror of
https://github.com/golang/go
synced 2024-11-26 08:58:09 -07:00
reflect: add Value.{Comparable,Equal}
For #46746 Change-Id: I879124974cdb55932cd9d07d3b384d49d5059857 Reviewed-on: https://go-review.googlesource.com/c/go/+/423794 Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
897ad2fe90
commit
acabf87127
2
api/next/46746.txt
Normal file
2
api/next/46746.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pkg reflect, method (Value) Comparable() bool #46746
|
||||
pkg reflect, method (Value) Equal(Value) bool #46746
|
@ -8214,3 +8214,366 @@ func TestValue_Len(t *testing.T) {
|
||||
t.Errorf("error is %q, want %q", e, wantStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValue_Comparable(t *testing.T) {
|
||||
var a int
|
||||
var s []int
|
||||
var i interface{} = a
|
||||
var iSlice interface{} = s
|
||||
var iArrayFalse interface{} = [2]interface{}{1, map[int]int{}}
|
||||
var iArrayTrue interface{} = [2]interface{}{1, struct{ I interface{} }{1}}
|
||||
var testcases = []struct {
|
||||
value Value
|
||||
comparable bool
|
||||
deref bool
|
||||
}{
|
||||
{
|
||||
ValueOf(32),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(int8(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(int16(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(int32(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(int64(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(uint8(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(uint16(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(uint32(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(uint64(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(float32(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(float64(1)),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(complex(float32(1), float32(1))),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(complex(float64(1), float64(1))),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf("abc"),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(true),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(map[int]int{}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([]int{}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
Value{},
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(&a),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(&s),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(&i),
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
ValueOf(&iSlice),
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
ValueOf([2]int{}),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([2]map[int]int{}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([0]func(){}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([2]struct{ I interface{} }{{1}, {1}}),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([2]struct{ I interface{} }{{[]int{}}, {1}}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([2]interface{}{1, struct{ I int }{1}}),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf([2]interface{}{[1]interface{}{map[int]int{}}, struct{ I int }{1}}),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
ValueOf(&iArrayFalse),
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
ValueOf(&iArrayTrue),
|
||||
true,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, cas := range testcases {
|
||||
v := cas.value
|
||||
if cas.deref {
|
||||
v = v.Elem()
|
||||
}
|
||||
got := v.Comparable()
|
||||
if got != cas.comparable {
|
||||
t.Errorf("%T.Comparable = %t, want %t", v, got, cas.comparable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ValueEqualTest struct {
|
||||
v, u any
|
||||
eq bool
|
||||
vDeref, uDeref bool
|
||||
}
|
||||
|
||||
var equalI interface{} = 1
|
||||
var equalSlice interface{} = []int{1}
|
||||
var nilInterface interface{}
|
||||
var mapInterface interface{} = map[int]int{}
|
||||
|
||||
var valueEqualTests = []ValueEqualTest{
|
||||
{
|
||||
Value{}, Value{},
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
true, true,
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
1, 1,
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
int8(1), int8(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
int16(1), int16(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
int32(1), int32(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
int64(1), int64(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
uint(1), uint(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
uint8(1), uint8(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
uint16(1), uint16(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
uint32(1), uint32(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
uint64(1), uint64(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
float32(1), float32(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
float64(1), float64(1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
complex(1, 1), complex(1, 1),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
complex128(1 + 1i), complex128(1 + 1i),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
func() {}, nil,
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
&equalI, 1,
|
||||
true,
|
||||
true, false,
|
||||
},
|
||||
{
|
||||
&equalSlice, []int{1},
|
||||
false,
|
||||
true, false,
|
||||
},
|
||||
{
|
||||
map[int]int{}, map[int]int{},
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
(chan int)(nil), nil,
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
(chan int)(nil), (chan int)(nil),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
&equalI, &equalI,
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
struct{ i int }{1}, struct{ i int }{1},
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
struct{ i int }{1}, struct{ i int }{2},
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
&nilInterface, &nilInterface,
|
||||
true,
|
||||
true, true,
|
||||
},
|
||||
{
|
||||
1, ValueOf(struct{ i int }{1}).Field(0),
|
||||
true,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
&mapInterface, &mapInterface,
|
||||
false,
|
||||
true, true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestValue_Equal(t *testing.T) {
|
||||
for _, test := range valueEqualTests {
|
||||
var v, u Value
|
||||
if vv, ok := test.v.(Value); ok {
|
||||
v = vv
|
||||
} else {
|
||||
v = ValueOf(test.v)
|
||||
}
|
||||
|
||||
if uu, ok := test.u.(Value); ok {
|
||||
u = uu
|
||||
} else {
|
||||
u = ValueOf(test.u)
|
||||
}
|
||||
if test.vDeref {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if test.uDeref {
|
||||
u = u.Elem()
|
||||
}
|
||||
|
||||
if r := v.Equal(u); r != test.eq {
|
||||
t.Errorf("%s == %s got %t, want %t", v.Type(), u.Type(), r, test.eq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3246,6 +3246,92 @@ func (v Value) CanConvert(t Type) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Comparable reports whether the type of v is comparable.
|
||||
// If the type of v is an interface, this checks the dynamic type.
|
||||
// If this reports true then v.Interface() == x will not panic for any x.
|
||||
func (v Value) Comparable() bool {
|
||||
k := v.Kind()
|
||||
switch k {
|
||||
case Invalid:
|
||||
return false
|
||||
|
||||
case Bool,
|
||||
Int, Int8, Int16, Int32, Int64,
|
||||
Uint, Uint8, Uint16, Uint32, Uint64,
|
||||
Uintptr,
|
||||
Float32, Float64, Complex64, Complex128,
|
||||
Chan:
|
||||
return true
|
||||
|
||||
case Array:
|
||||
if v.Type().Len() == 0 {
|
||||
return v.Type().Comparable()
|
||||
}
|
||||
|
||||
switch v.Type().Elem().Kind() {
|
||||
case Interface, Array, Struct:
|
||||
for i := 0; i < v.Type().Len(); i++ {
|
||||
if !v.Index(i).Comparable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
default:
|
||||
return v.Index(0).Comparable()
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
case Func:
|
||||
return false
|
||||
|
||||
case Interface:
|
||||
return v.Elem().Comparable()
|
||||
|
||||
case Map:
|
||||
return false
|
||||
|
||||
case Pointer:
|
||||
return true
|
||||
|
||||
case Slice:
|
||||
return false
|
||||
|
||||
case String:
|
||||
return true
|
||||
|
||||
case Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if !v.Field(i).Comparable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case UnsafePointer:
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Equal reports true if v is equal to u.
|
||||
func (v Value) Equal(u Value) bool {
|
||||
if !v.IsValid() || !u.IsValid() {
|
||||
return v.IsValid() == u.IsValid()
|
||||
}
|
||||
|
||||
if v.Comparable() || u.Comparable() {
|
||||
return valueInterface(v, false) == valueInterface(u, false)
|
||||
}
|
||||
|
||||
if u.Kind() == Interface && v.kind() == Interface { // this case is for nil interface value
|
||||
return v.Elem().Equal(u.Elem())
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 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.
|
||||
func convertOp(dst, src *rtype) func(Value, Type) Value {
|
||||
|
Loading…
Reference in New Issue
Block a user