fix(container): Add NilChecker Support to gmap, gset, and gtree for Typed Nil Issue Resolution#4605
Conversation
- 在KVMap、ListKVMap、TSet和各种树结构中引入NilChecker类型 - 实现RegisterNilChecker方法用于注册自定义nil检查函数 - 添加isNil方法统一处理nil值判断逻辑 - 修改GetOrSet、AddIfNotExist等相关方法使用新的nil检查机制 - 为所有支持的数据结构添加相应的单元测试验证功能正确性 - 更新红黑树比较器调用方式以支持泛型参数传递
There was a problem hiding this comment.
Pull request overview
This pull request introduces a NilChecker mechanism to the gmap, gset, and gtree containers to address the typed nil problem in Go. The feature allows users to register custom nil checker functions that determine whether a value should be treated as nil, solving the issue where typed nil pointers (e.g., (*Student)(nil)) are not correctly identified when using the standard any(value) == nil check.
Changes:
- Added
NilCheckertype and registration methods across gmap, gset, and gtree packages - Updated nil-checking logic in Set/GetOrSet operations to use custom checkers when available
- Added comprehensive test coverage for the new functionality across all three container types
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| container/gmap/gmap_hash_k_v_map.go | Added NilChecker type, registration method, and updated nil checks in GetOrSetFuncLock and doSetWithLockCheck |
| container/gmap/gmap_list_k_v_map.go | Added nilChecker field and updated nil checks in GetOrSetFuncLock and SetIfNotExist* methods |
| container/gmap/gmap_z_unit_k_v_map_test.go | Added test for typed nil handling with custom nil checker |
| container/gmap/gmap_z_unit_list_k_v_map_test.go | Added test for typed nil handling with custom nil checker |
| container/gset/gset_t_set.go | Added NilChecker type, registration method, and updated nil checks in AddIfNotExist* methods |
| container/gset/gset_z_unit_t_set_test.go | Added test for typed nil handling with custom nil checker |
| container/gtree/gtree_k_v_avltree.go | Added NilChecker type, registration method, and updated nil check in doSet |
| container/gtree/gtree_k_v_btree.go | Added nilChecker field and updated nil check in doSet |
| container/gtree/gtree_k_v_redblacktree.go | Added nilChecker field and updated nil check in doSet |
| container/gtree/gtree_redblacktree.go | Fixed comparator call to use generic version |
| container/gtree/gtree_z_k_v_tree_test.go | Added tests for typed nil handling across AVL, B-tree, and Red-Black tree implementations |
Comments suppressed due to low confidence (3)
container/gmap/gmap_hash_k_v_map.go:324
- The SetIfNotExist method does not utilize the nil checker mechanism. When the value is nil (according to the custom nil checker), it should not be set in the map. This is inconsistent with other methods like doSetWithLockCheck and GetOrSetFuncLock. Add an isNil check before setting the value to maintain consistency with the PR's goal of filtering typed nil values.
func (m *KVMap[K, V]) SetIfNotExist(key K, value V) bool {
m.mu.Lock()
defer m.mu.Unlock()
if m.data == nil {
m.data = make(map[K]V)
}
if _, ok := m.data[key]; !ok {
m.data[key] = value
return true
}
return false
}
container/gmap/gmap_hash_k_v_map.go:351
- The SetIfNotExistFuncLock method does not utilize the nil checker mechanism. Similar to SetIfNotExist, it should check if the value returned by f() is nil (according to the custom nil checker) before setting it in the map. This creates inconsistent behavior compared to GetOrSetFuncLock and other methods that were updated in this PR.
func (m *KVMap[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {
m.mu.Lock()
defer m.mu.Unlock()
if m.data == nil {
m.data = make(map[K]V)
}
if _, ok := m.data[key]; !ok {
m.data[key] = f()
return true
}
return false
}
container/gmap/gmap_hash_k_v_map.go:333
- The SetIfNotExistFunc method does not check for nil values. While it delegates to SetIfNotExist, which also doesn't check for nil, this creates a gap in the nil checker implementation. Consider evaluating f() and checking isNil before calling SetIfNotExist to ensure consistent behavior with the pattern established in ListKVMap.
func (m *KVMap[K, V]) SetIfNotExistFunc(key K, f func() V) bool {
if !m.Contains(key) {
return m.SetIfNotExist(key, f())
}
return false
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <[email protected]>
描述
本PR为
gmap、gset和gtree容器引入了NilChecker机制,以解决Go语言中的typed nil问题。该实现允许用户注册自定义的nil检查函数来确定值是否应被视为nil,这对于处理那些会被存储到容器中的typed nil值特别有用。情况描述
当前
gmap等容器的泛型容器存在对value的nil值无法正确过滤的问题,例如以下例子中如果使用默认的if any(value) != nil去判断就会得到错误的结果,原因是会出现带有类型的(*Student)(nil)直接和nil比较或者使用any强转都是不对的,使用反射可以解决但是性能太差了,所以换个思虑我们让用户自己决定如何判断nil就能解决这个问题变更内容
NilChecker类型定义nilChecker字段来存储自定义nil检查函数RegisterNilChecker方法,允许用户注册自定义nil检查逻辑isNil内部方法,优先使用自定义nil检查函数或回退到默认的any(v) == nil检查