golang 中的 nil的场景分析

源码中的 nil 是这样定义的

// 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

所以 nil 可以理解为这些类型的零值,声明一个变量在没有赋值的情况下,变量处于零值状态。

场景一

func t1() {
 var i interface{}
 var p *int

 fmt.Println("p==i", p == i)
 fmt.Println("i=", i, "i==null", i == nil)
 fmt.Println("p=", p, "p==nil", p == nil)
 fmt.Println("i TypeOf=", reflect.TypeOf(i), "i ValueOf", reflect.ValueOf(i))
 fmt.Println("p TypeOf=", reflect.TypeOf(p), "p ValueOf", reflect.ValueOf(p))
 i = p
 fmt.Println("---")
 fmt.Println("p==i", p == i)
 fmt.Println("i=", i, "i==null", i == nil)
 fmt.Println("p=", p, "p==nil", p == nil)
 fmt.Println("i TypeOf=", reflect.TypeOf(i), "i ValueOf", reflect.ValueOf(i))
 fmt.Println("p TypeOf=", reflect.TypeOf(p), "p ValueOf", reflect.ValueOf(p))

}

真相是 i 刚开始没有类型,而 p 是有类型,所以 p 和 i 都等于 nil,但是 == 可以理解为 php 或者 js 里面的 === 全等,既要类型相等,也要值相等。

在 i = p 之后,p 和 i 类型和值保持了一致所以会相等,但是 i 已经不等于 nil 了,因为 nil 是 interface 的 0 值,或者说 i 已经指向 p ,i 现在是个有类型状态而非 0 值状态。

结果如下

p==i false
i= <nil> i==null true
p= <nil> p==nil true
i TypeOf= <nil> i ValueOf <invalid reflect.Value>
p TypeOf= *int p ValueOf <nil>
---
p==i true
i= <nil> i==null false
p= <nil> p==nil true
i TypeOf= *int i ValueOf <nil>
p TypeOf= *int p ValueOf <nil>

场景二

func t3() {
 f1 := func(i interface{}) bool {
  return i == nil
 }

 var a *int
 fmt.Println(f1(a)) // false
 fmt.Println(f1(nil)) // true
}

a 传递到 func 里面,被转成 interface,这个 interface 是有类型的 interface,相当于赋值了一下 i=a ,所以 i 的状态不是 interface 的零值状态 ,和 interface 零值状态的 nil 当然是不相等

场景三

type A struct {
}

func (A) a1() int {
 return 123
}

func (*A) a2() int {
 return 321
}

type B interface {
}

func t2() {
 var a A
 var ap *A
 var b B
 var bp *B

 fmt.Println("a=", a, "a.a1()", a.a1(), a.a2()) //a= {} a.a1() 123 321; a == nil 会抛错 struct 不能和 nil 进行比较
 fmt.Println("ap=", ap, "ap==nil", ap == nil) //ap= <nil> ap==nil true

 fmt.Println("b=", b, " b==nil:", b == nil)  // b= <nil> b==nil: true
 fmt.Println("bp=", bp, " bp==nil:", bp == nil) //bp= <nil> bp==nil: true
}

结构体的 0 值为 {}

到此这篇关于golang 中的 nil的场景分析的文章就介绍到这了,更多相关golang 中的 nil内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang 如何替换掉字符串里面的换行符\n

    原始字符串: -----BEGIN LICENSE KEY-----\nL/+HAwEBB2xpY2Vuc2UB/4gAAQIBB1BheWxvYWQBCgABCVNpZ25hdHVyZQEKAAAA\n/gPo/4gB/gHd/7AQABpsaWNlbnNlLW1nci9jb25maWcuUGF5bG9hZP+BAwEBB1Bh\neWxvYWQB/4IAAQoBBUFwcElkAQwAAQZBcHBLZXkBDAABCVN0YXJ0VGltZQEMAAEE\nRGF5cwEEAAEGQWVz

  • 基于golang uint8、int8与byte的区别说明

    简单说明 uint8与byte可以说是一样的,因为文档中有这样的定义: The Go Programming Language Specification Numeric types uint8 the set of all unsigned 8-bit integers (0 to 255) byte alias for uint8 也就是说,我们在需要将这两种类型转换为string的时候都是可以直接使用string()来进行的. 而int8的取值范围为-128~127,所以int8不能直接与

  • Golang 并发以及通道的使用方式

    Golang最擅长的就是并发编程,使用Golang可以很方便的进行并发编程.先看一段普通的代码 package main import ( "fmt" "time" ) func Foo(i int) { fmt.Printf("%d will sleep\n", i) time.Sleep(5 * time.Second) fmt.Printf("%d wake up\n", i) } func main() { for i

  • Golang Printf,Sprintf,Fprintf 格式化详解

    1.`Sprintf` 则格式化并返回一个字 符串而不带任何输出. s := fmt.Sprintf("是字符串 %s ","string") 2. fmt.Println(s) // 是字符串 %s 对应 是字符串 string 3.可以使用 `Fprintf` 来格式化并输出 fmt.Fprintf(os.Stderr, "格式化 %s\n", "error") 顺带说一下格式化的符号: /* %v 输出结构体 {10 3

  • 解决golang gin框架跨域及注解的问题

    在golang的路上缓慢前进 Gin框架 跨域问题的解说与方法 代码如下: package main import ( "github.com/gin-gonic/gin" "awesomeProject/app/app_routers" "strings" "fmt" "net/http" ) /* 路由初始化*/ var ( engine = gin.Default() ) func main() {

  • golang创建文件目录os.Mkdir,os.MkdirAll的区别说明

    如下所示: os.Mkdir("abc", os.ModePerm) //创建目录 os.MkdirAll("dir1/dir2/dir3", os.ModePerm) //创建多级目录 首先,试图从一个Go可执行文件创建一组嵌套目录(如'dir1/dir2/dir3'),并打印错误出来看看. err:=os.Mkdir("dir1/dir2/dir3",os.ModePerm) if err!=nil{ fmt.Println(err) } r

  • 手把手教你vscode配置golang开发环境的步骤

    1.下载安装Golang https://golang.google.cn/dl/ 一路下一步即可 2.下载安装Vscode https://visualstudio.microsoft.com/zh-hans/ 3.检查Golang是否安装成功 4.设置Golang 环境变量 go env -w GO111MODULE=on Golang1.16默认开启,1.16一下需要执行这条命令 go env -w GOPROXY=https://goproxy.cn,direct 设置七牛CDN 我的环

  • golang 中的 nil的场景分析

    源码中的 nil 是这样定义的 // 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 所以 nil 可以理解为这些类型的零值,声明

  • React中的Context应用场景分析

    Context定义和目的 Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树的逐层传递 props. 应用场景 哪些数据会需要共享? Context 设计目的是为了共享那些对于一个组件树而言是**"全局"的数据**,例如当前认证的用户.主题或首选语言. 使用步骤 1. 创建并初始化Context const MyContext = createContex(defaultValue); 创建一个 Context 对象.当 React 渲染一个订阅了这个 Cont

  • golang中的nil接收器详解

    我们先看一个简单的例子,我们自定义一个错误,用来把多个错误放在一起输出: type CustomError struct {errors []string} func (c *CustomError) Add(err string) {c.errors = append(c.errors, err)} func (c *CustomError) Error() string {return strings.Join(c.errors, ";")} 因为实现了Error() string

  • Golang::slice和nil的对比分析

    我就废话不多说了,大家还是直接看代码吧~ package main import ( "fmt" ) func main() { var s1 []int if s1 == nil { fmt.Println("s1==nil") } else { fmt.Println("s1!=nil") } var arr = [5]int{} s1 = arr[:] if s1 == nil { fmt.Println("s1==nil&quo

  • SQL语句中JOIN的用法场景分析

    记录:256 写SQL最高境界:SELECT * FROM 表名.当然这是一句自嘲.探究一下SQL语句中JOIN的用法,直到经历这个场景,变得想验证一下究竟. 一.场景 把关系型数据库A中表TEST_TB01和TEST_TB02迁移到大数据平台M(MaxCompute大数据平台).TEST_TB01单表1000万条记录,TEST_TB02单表80万条记录. 在关系型数据库中,TEST_TB01和TEST_TB02中有主键约束.在产生新增业务数据时,不会存在重复数据插入.但是,当数据迁移到大数据平

  • 利用consul在spring boot中实现分布式锁场景分析

    因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了. 这里列举一个最简单的场景,假如有一个智能售货机,由于机器本身的原因不能同一台机器不能同时出两个商品,这就要求在在出货流程前针对同一台机器在同一时刻出现并发 创建订单时只能有一笔订单创建成功,但是订单服务是多节点部署的,所以就不得不用到分布式锁了. 以上只是一种简单的业务场景,在各种大型互联网实际应用中,需要分布式锁的业务场景会更多,综合比较了业界基于各种

  • Golang时间处理中容易踩的坑分析解决

    目录 简介 类型 时区 小心有坑 时间解析的使用场景 时间操作 获取当前时间 时区设置 时间格式化(时间类型转字符串) 时间类型转时间戳 时间戳转时间类型 时间字符串转时间类型 时间计算 获取时间类型具体内容 时间加减 时间间隔(耗时) 时间取整(向上取整向下取整) 拓展 json时间转换 简介 在各个语言之中都有时间类型的处理,因为这个地球是圆的(我仿佛在讲废话),有多个时区,每个时区的时间不一样,在程序中有必要存在一种方式,或者说一种类型存储时间,还可以通过一系列的方法转换成不同国家的时间.

  • 详解Golang中select的使用与源码分析

    目录 背景 select 流程 背景 golang 中主推 channel 通信.单个 channel 的通信可以通过一个goroutine往 channel 发数据,另外一个从channel取数据进行.这是阻塞的,因为要想顺利执行完这个步骤,需要 channel 准备好才行,准备好的条件如下: 1.发送 缓存有空间(如果是有缓存的 channel) 有等待接收的 goroutine 2.接收 缓存有数据(如果是有缓存的 channel) 有等待发送的 goroutine 对channel实际使

  • JDK1.8中的ConcurrentHashMap使用及场景分析

    ConcurrentHashMap 的初步使用及场景: ConcurrentHashMap 是 J.U.C 包里面提供的一个线程安全并且高效的 HashMap,所以ConcurrentHashMap 在并发编程的场景中使用的频率比较高,那么我们就从ConcurrentHashMap 的使用上以及源码层面来分析 ConcurrentHashMap 到底是如何实现安全性的 api 使用: ConcurrentHashMap 是 Map 的派生类,所以 api 基本和 Hashmap 是类似,主要就是

  • java中ThreadLocal的应用场景实例分析

    说到线程的安全,我们可以通过ThreadLocal来解决.但作为一种强大的变量,它的应用场景远不止如此.在各类的框架中,我们依然可以使用来对它们进行管理.同时在使用ThreadLocal时需要注意内存泄漏的问题.下面我们就这两点进行分析,并带来对应代码的展示. 1.各种框架中的应用 Spring框架的事务管理中使用ThreadLocal来管理连接,每个线程是单独的连接,当事务失败时不能影响到其他线程的事务过程或结果,还有大家耳闻目睹的ORM框架.Mybatis也是用ThreadLocal管理,S

随机推荐