golang中空值判断函数,支持任意类型的空值判断

使用反射方式对any任意类型的数据是否为空判断, 可判断时间对象是否为空, 可判断所有数字类型,指针类型和结构体字符串是否为空

判断规则:

bool类型因为只有true和false 所以 全部视为非空

nil 类型全部视为空

所有数字类型的 零值全部视为空

对应指针类型数据,只要是非nil 则视为非空

对于时间类型结构体或者其他带有 IsZero()方法的结构体 动态调用IsZero()方法来判断是否为空

go代码实现

Go 复制代码
import (
	"reflect"
)

// 使用反射方式对any任意类型的数据是否为空判断, 可判断时间对象是否为空, 可判断所有数字类型,指针类型和结构体字符串是否为空

// 	判断规则:
// 	bool类型因为只有true和false 所以 全部视为非空
// 	nil 类型全部视为空
// 	所有数字类型的 零值全部视为空
// 	对应指针类型数据,只要是非nil 则视为非空
// 	对于时间类型结构体或者其他带有 IsZero()方法的结构体 动态调用IsZero()方法来判断是否为空
//
// @author: tekintian <tekintian@gmail.com>
// @see https://dev.tekin.cn
func IsEmpty(data interface{}) bool {
	rv := reflect.ValueOf(data)
	rvk := rv.Kind()
	switch rvk {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		return rv.IsZero()
	case reflect.Uintptr, reflect.Map, reflect.Slice, reflect.Pointer, reflect.UnsafePointer:
		return rv.IsNil() // 指针类型数据全部调用 IsNil() 进行判断,非nil的指针视为非空
	case reflect.String:
		return rv.Len() == 0
	case reflect.Struct:
		if rv.MethodByName("IsZero").IsValid() {
			// 动态调用结构体中的 IsZero 方法
			rt := rv.MethodByName("IsZero").Call([]reflect.Value{}) // call后面的参数即是要调用方法的参数 []reflect.Value{} 表示无参数
			return len(rt) > 0 && rt[0].Bool()                      // IsZero方法的返回值只有一个bool,
		} else {
			// 对值的零值类型进行深度比较
			return reflect.DeepEqual(rv.Interface(), reflect.Zero(rv.Type()).Interface())
		}
	case reflect.Invalid: // nil值的reflect类型就是 Invalid
		return true // nil也算是空值
	}

	return false // 其他情况默认非空
}

单元测试用例

Go 复制代码
import (
	"gotms/utils"
	"testing"
	"time"
)

type DemoSt struct {
	Name    string
	Items   []DemoItem
	Data    interface{}
	Created time.Time
}
type DemoItem struct {
	Name string
}

func TestIsEmpty(t *testing.T) {
	cases := []struct {
		input    interface{}
		expected bool
	}{
		{input: time.Now(), expected: false},
		{input: DemoSt{}.Created, expected: true}, // 空时间对象 这个是未初始化的时间对象 视为空
		{input: time.Time{}, expected: true},      // 空时间对象 已经初始化
		{input: false, expected: false},
		{input: DemoSt{}.Items, expected: true}, // 这里的DemoSt{}.Items 是一个不可达的对象,即未初始化的对象 视为空
		{input: DemoSt{}.Data, expected: true},  // nil
		{input: "", expected: true},
		{input: 0.0, expected: true},
		{input: nil, expected: true},
		{input: complex(0, 0), expected: true}, // 复数的判断
		{input: complex(2, 1), expected: false},
	}
	for _, v := range cases {
		ret := utils.IsEmpty(v.input)
		if ret != v.expected {
			t.Fatalf("%v test failed: expected: %v, got: %v", v.input, v.expected, ret)
		}
	}
}
相关推荐
用余生去守护14 分钟前
python报错系列(16)--pyinstaller ????????
开发语言·python
数据小爬虫@18 分钟前
利用Python爬虫快速获取商品历史价格信息
开发语言·爬虫·python
向宇it20 分钟前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
莫名其妙小饼干37 分钟前
网上球鞋竞拍系统|Java|SSM|VUE| 前后端分离
java·开发语言·maven·mssql
十年一梦实验室1 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
最爱番茄味1 小时前
Python实例之函数基础打卡篇
开发语言·python
程序猿000001号1 小时前
探索Python的pytest库:简化单元测试的艺术
python·单元测试·pytest
Oneforlove_twoforjob2 小时前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
engchina2 小时前
如何在 Python 中忽略烦人的警告?
开发语言·人工智能·python
向宇it2 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎