diff --git a/doc/go1.22.html b/doc/go1.22.html index c32669b13a4..7fee6a09ee8 100644 --- a/doc/go1.22.html +++ b/doc/go1.22.html @@ -100,6 +100,20 @@ Do not send CLs removing the interior tags from such phrases. +
reflect
+
+

+ The Value.IsZero + method will now return true for a floating-point or complex + negative zero, and will return true for a struct value if a + blank field (a field named _) somehow has a + non-zero value. + These changes make IsZero consistent with comparing + a value to zero using the languague == operator. +

+
+
+

Ports

diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index afd2d2ef79c..c2a987f45e9 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -1396,6 +1396,11 @@ func TestIsNil(t *testing.T) { NotNil(fi, t) } +func setField[S, V any](in S, offset uintptr, value V) (out S) { + *(*V)(unsafe.Add(unsafe.Pointer(&in), offset)) = value + return in +} + func TestIsZero(t *testing.T) { for i, tt := range []struct { x any @@ -1429,14 +1434,14 @@ func TestIsZero(t *testing.T) { {float32(1.2), false}, {float64(0), true}, {float64(1.2), false}, - {math.Copysign(0, -1), false}, + {math.Copysign(0, -1), true}, {complex64(0), true}, {complex64(1.2), false}, {complex128(0), true}, {complex128(1.2), false}, - {complex(math.Copysign(0, -1), 0), false}, - {complex(0, math.Copysign(0, -1)), false}, - {complex(math.Copysign(0, -1), math.Copysign(0, -1)), false}, + {complex(math.Copysign(0, -1), 0), true}, + {complex(0, math.Copysign(0, -1)), true}, + {complex(math.Copysign(0, -1), math.Copysign(0, -1)), true}, {uintptr(0), true}, {uintptr(128), false}, // Array @@ -1485,6 +1490,14 @@ func TestIsZero(t *testing.T) { {struct{ s []int }{[]int{1}}, false}, // incomparable struct {struct{ Value }{}, true}, {struct{ Value }{ValueOf(0)}, false}, + {struct{ _, a, _ uintptr }{}, true}, // comparable struct with blank fields + {setField(struct{ _, a, _ uintptr }{}, 0*unsafe.Sizeof(uintptr(0)), 1), true}, + {setField(struct{ _, a, _ uintptr }{}, 1*unsafe.Sizeof(uintptr(0)), 1), false}, + {setField(struct{ _, a, _ uintptr }{}, 2*unsafe.Sizeof(uintptr(0)), 1), true}, + {struct{ _, a, _ func() }{}, true}, // incomparable struct with blank fields + {setField(struct{ _, a, _ func() }{}, 0*unsafe.Sizeof((func())(nil)), func() {}), true}, + {setField(struct{ _, a, _ func() }{}, 1*unsafe.Sizeof((func())(nil)), func() {}), false}, + {setField(struct{ _, a, _ func() }{}, 2*unsafe.Sizeof((func())(nil)), func() {}), true}, // UnsafePointer {(unsafe.Pointer)(nil), true}, {(unsafe.Pointer)(new(int)), false}, diff --git a/src/reflect/value.go b/src/reflect/value.go index 06bbcf72147..ec75fcced9f 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1594,10 +1594,9 @@ func (v Value) IsZero() bool { case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: return v.Uint() == 0 case Float32, Float64: - return math.Float64bits(v.Float()) == 0 + return v.Float() == 0 case Complex64, Complex128: - c := v.Complex() - return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 + return v.Complex() == 0 case Array: // If the type is comparable, then compare directly with zero. if v.typ().Equal != nil && v.typ().Size() <= maxZero { @@ -1633,7 +1632,7 @@ func (v Value) IsZero() bool { n := v.NumField() for i := 0; i < n; i++ { - if !v.Field(i).IsZero() { + if !v.Field(i).IsZero() && v.Type().Field(i).Name != "_" { return false } }