【开发掉坑】go 中 interface 的 nil 判断

这篇具有很好参考价值的文章主要介绍了【开发掉坑】go 中 interface 的 nil 判断。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天介绍下 go 中的 interface(any)nil 判断,项目中遇到的一个小问题,知识遗忘了,再做个记录。

前言

最近在合作开发项目的过程中,发现小伙伴写了一段代码,示意代码如下:

package main

import(
	"encoding/json"
	"fmt"
)

type dataWrapper struct {
	data any
}

func convert(v any) *dataWrapper {
	d := new(dataWrapper)
	d.data = v
	return d
}

type sureData struct {
	Name string
}

func (d *dataWrapper) sureData() *sureData {
	buf, _ := json.Marshal(d.data)
	data := new(sureData)
	json.Unmarshal(buf, data)
	return data
}

type oldData struct {
	Name string
}

func main() {
	var data *oldData 
	fmt.Println("is nil: ", data == nil) // true

	sd := convert(data).sureData()
	fmt.Println("is nil: ", sd == nil) // false

	if sd == nil {
		// 逻辑代码
	} else {
		// 逻辑代码
	}
}

输出:

is nil:  true
is nil:  false

由于该代码仓库是为了让其他项目使用,基于之前的老项目抽离出来的,老项目的结构体和新项目不同,但是字段都是一样的,要进行结构体转换,偷懒用 jsonMarshalUnmarshal 来做的(这种方式不认同,对调用方不友好,而且效率还差)。

这里的 dataWrapper 就是进行结构体转换的一个封装,最终使用 sureData 方法获取真正的结构体数据。

代码简单,可以看到这里的 sureData 方法获取的数据肯定不为空,因为它在方法里做了 new(sureData) 了,返回的结构体肯定不为空。

代码看到这里,想要使其能正确地判断 nil,对 sureData 方法进行了如下修改(当然只是做示例用,真实场景中不推荐):

func (d *dataWrapper) sureData() *sureData {
	if d.data == nil {
		return nil
	}
	buf, _ := json.Marshal(d.data)
	data := new(sureData)
	json.Unmarshal(buf, data)
	return data
}

但是运行查看输出结果和刚刚没区别

is nil:  true
is nil:  false

为什么传给 dataWrppernil 值再判断就不为 nil 了呢?按理说 sureData 得到的值应该是 nil 才对,这就引出了今天主题,判断 interface(any) 是否为 nil

原理解析

先看下 interface 的底层结构,分为两种:包含 methodiface 和不包含 methodeface,也就是 empty interface

本篇介绍基于 go1.20 版本,源码在:src/runtime/runtime2.go,具体结构如下

type iface struct {
	tab  *itab
	data unsafe.Pointer
}

type eface struct {
	_type *_type
	data  unsafe.Pointer
}

具体的 iface, eface 结构就不在此篇介绍了。

结论:当我们判断一个 interface 的值是否为 nil 时,需要这个值的动态类型和动态值都为 nil 时,这个 interface 才会是 nil

可以看以下例子来加深印象:

package main

func main() {
	var a any = nil
	var b any = (*string)(nil)
	println(a==nil) // true
	println(b==nil) // false
}

解决方案

  1. 反射

注意查看 nil 的定义(源码:src/builtin/builtin.go),使用反射进行 nil 判断时需要注意类型只能是 pointer, channel, func, interface, map, or slice type,使用其他类型会直接 panic

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
func IsNil(v any) bool {
	valueOf := reflect.ValueOf(v)

	k := valueOf.Kind()

	switch k {
	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
		return valueOf.IsNil()
	default:
		return v == nil
	}
}
  1. interface 底层结构

可以模拟 eface 的结构来进行 nil 判断,不建议这么使用,还是用 reflect 官方包比较好。

type eface struct {
	rtype unsafe.Pointer
	data  unsafe.Pointer
}

func IsNil(obj any) bool {
	return (*eface)(unsafe.Pointer(&obj)).data == nil
}
  1. 明确知道 interface 类型的值

可以使用类型断言,建议使用。

type Dog struct{}
type Cat struct{}
func IsNil(obj any) bool {
	switch obj.(type) {
	case *Dog:
		return obj.(*Dog) == nil
	case *Cat:
		return obj.(*Cat) == nil
	}
	return obj == nil
}

总结

本篇以实际开发过程中的一个例子作为引导,介绍了 go 中的 interfacenil 判断的坑点。

解释了其原理:只有当类型和值都为空时,接口才为空。文章来源地址https://www.toymoban.com/news/detail-808622.html

参考

  • golang interface判断为空nil
  • Golang interface的类型断言是如何实现

到了这里,关于【开发掉坑】go 中 interface 的 nil 判断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go 语言 nil 空值

    在 Go 语言中, nil 是一个预定义的标识符,用于表示某些类型的零值或空值。 nil 在 Go 语言中可以表示以下几种类型的零值或空值: 指针类型:表示一个指向空地址的指针,即指针不指向任何有效的内存地址。 接口类型:表示一个空接口,即接口没有关联任何值。 函数类型

    2024年02月11日
    浏览(37)
  • Go 空切片与nil切片

    在 Go 语言中,空切片和 nil 切片是两种不同的概念。 空切片是一个长度和容量都为 0 的切片。你可以通过 make 函数或者切片字面量来创建一个空切片,例如 s := make([]int, 0) 或者 s := []int{}。 空切片不是 nil,即 s != nil。 空切片已经分配了内存空间,所以你可以直接向空切片中

    2024年02月20日
    浏览(36)
  • Go语言中的空和nil

    Go语言中的空和nil 在 Go 语言中,\\\"空\\\"和\\\"nil\\\"是两个不同的概念,分别适用于不同的数据类型和用途。 在 Go 中,每种数据类型都有一个默认的零值,也被称为\\\"空\\\"值。这是在创建变量但未显式初始化时自动分配给变量的值。空值对于不同类型的变量来说是不同的,例如: 数值类

    2024年02月13日
    浏览(92)
  • Go 空切片 VS nil切片

    在 Go 语言中,空切片和 nil 切片是两种不同的概念。 空切片是一个长度和容量都为 0 的切片。你可以通过 make 函数或者切片字面量来创建一个空切片,例如 s := make([]int, 0) 或者 s := []int{}。 空切片不是 nil,即 s != nil。 空切片已经分配了内存空间,所以你可以直接向空切片中

    2024年02月20日
    浏览(49)
  • go数据类型-空结构体、空接口、nil

    有经验的开发人员都知道,所有的空结构体是指向一个 zerobase的地址,而且大小为0 一般用来作结合map作为set 或者 在channel中 传递信号。 能看到当一个空结构体中,包含了其他类型的变量,就不指向 zerobase。 go中的接口都是隐式的,增加的封装的灵活性,也为阅读源码增加了

    2024年02月05日
    浏览(55)
  • 【Golang map并发报错】panic: assignment to entry in nil map

    go并发写 map[string]interface{} 数据的时候,报错: panic: assignment to entry in nil map 多个key同时操作一个map时,如: test[key1] = 1 test[key2] = \\\"a\\\" test[key3] = true 就会遇到并发nil值报错,什么test[key-xxx] = make()根本不行。 用异步sync.Map解决: Lock锁那个比较麻烦,不建议使用。推荐使用sync

    2024年01月19日
    浏览(33)
  • Golang 接口(interface)

    原创比较累,希望大家能点点赞,对我的支持。你们的支持,就是我的动力。 1. 接口实现 在 Go 中,接口是一种抽象类型,它定义了一组方法签名,但没有实现。接口用于描述对象应该具有的方法集合,而不是具体的实现方式。 接口的定义使用 `type` 和 `interface` 。例如

    2024年02月05日
    浏览(35)
  • 【Golang】go编程语言适合哪些项目开发?

    前言 在当今数字化时代,软件开发已成为各行各业的核心需求之一。 而选择适合的编程语言对于项目的成功开发至关重要。 本文将重点探讨Go编程语言适合哪些项目开发,以帮助读者在选择合适的编程语言时做出明智的决策。 Go 编程语言适合哪些项目开发? Go是由Google开发

    2024年02月04日
    浏览(76)
  • Go invalid memory address or nil pointer dereference错误 空指针问题

    Go 指针声明后赋值,出现 panic: runtime error: invalid memory address or nil pointer dereference,这种是内存地址错误。 首先我们要了解 指针,指针地址 在 Go 中 * 代表取指针地址中存的值, 代表取一个值的地址 对于指针,我们一定要明白指针储存的是一个值的地址,但本身这个指针也需

    2024年02月05日
    浏览(55)
  • golang any 之中的类型及 interface 接口

    在 golang 之中 any 类型,从字面意思上看是任意类型,这很类似我们在 C#、C++ 之中的任意指针类型 void*(原生),C# 之中诡异的 object。 any 是一个接口类型,其语法声明为: 即 interface{} 等于 any,这是一种类似 C++ 之中语法为: using 别名 = 类型; 别名定义方式,C# 这块只允许

    2024年01月23日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包