前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Go系列:为什么这个变量不为nil

Go系列:为什么这个变量不为nil

原创
作者头像
用户9805946
发布2024-11-06 22:47:30
发布2024-11-06 22:47:30
670
举报
文章被收录于专栏:Go

前言

今天在写代码时,发现一个结构体使用json.Marshal后值为“null”,最后定位到这个函数

代码语言:txt
复制
func toString(obj any) string {
	if obj == nil {
		return ""
	}
	bytes, _ := json.Marshal(obj)
	return string(bytes)
}

经过测试发现

代码语言:txt
复制
var t []string
fmt.Println(toString1(t))

输出结果
null
	

分析

经过分析,原因是:

  • interface{} 的值不是任意类型,而是 interface{} 类型
  • 接口包含两个字的大小,类似于 (type, value)

所以:

  1. 当定一个一个interface{}变量 var x interface{} 此时,{type=空,value=空},此时x == nil
  2. 当将一个类型赋值到这个变量 var s []string x = s 那么至少type就会有值了,此时 x != nil, 因为相当于x其实有值了,虽然value为空,但是type不是空,所以不能认为是一个空interface{}

确认

可以通过debug确认

代码语言:go
复制
func main()  {
	var x any
	time.Sleep(1 * time.Second)

    var s []string
	x = s
	time.Sleep(1 * time.Second)
	
	_ = x
}

对sleep处加断点

运行第一个断点处,x变量为

代码语言:go
复制
x = {interface{}}nil

运行到第二个断点处,x变量为

代码语言:go
复制
x = {interface{}|[]string} []string(nil)

可以看到当复制一个零值的字符串切片时,此时x的类型已经改变

如何修改

两个方法

1. 范型

此时参数obj是一个切片,传入零值切片后,obj也是零值切片

代码语言:go
复制
func toString[T any](obj []T) string {
	if obj == nil {
		return ""
	}
	bytes, _ := json.Marshal(obj)
	return string(bytes)
}

2. 反射判断

在函数内部,通过反射,判断obj是否时零值

代码语言:go
复制
func toString(obj any) string {
	v := reflect.ValueOf(obj)
	if v.IsZero() {
		return ""
	}

	if obj == nil {
		return ""
	}

	bytes, _ := json.Marshal(obj)
	return string(bytes)
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 分析
  • 确认
  • 如何修改
    • 1. 范型
    • 2. 反射判断
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档