后端技术总结

  • 首页
  • github
  • About Me
  1. 首页
  2. Golang
  3. 正文

golang 判断interface是否为空nil

2020年9月2日 3404点热度 2人点赞 0条评论
内容纲要

前言

interface很好用,可以存取任意类型,但我们在使用这个值类型的时候我们往往又需要知道该interface是属于哪种类型的,以便正确使用这个值。比如,如果我们提前知道该interface为int,则都是这样使用:

var a interface{}
a = 5
fmt.Println(2*a.(int))

而往往我们interface可能会存放多种不同类型的数据,为了健壮,在使用时我们需要判断interface里面存放的到底为何种类型的数据,以及这些数据是否为空?比如你引用了一个类型里面的空对象是很容易引发panic的。

我们通过什么方式判断interface是否为空呢?

先明确一点:一个interface里面存在动态类型和动态值,只有当动态类型和动态值都为空时,该interface才为空(nil)
比如:

package main

import "fmt"

func main(){

       var a interface{} = nil 
       var b interface{} = (*int)(nil) 

       fmt.Println(a==nil) // output: true
       fmt.Println(b==nil) // output: false
}

上面例子中,因为a本身就是nil,所以在比较时结果为true不难理解。而b因为是属于动态类型为(*int),并非nil,所以在比较时返回false。那我们一般又是通过哪种方式来判断interface是属于什么类型,以及动态值是否为空呢?这个时候我们要用上reflect反射了,如下:

package main

import (
    "fmt"
    "reflect"
)

type A struct{}

func main() {
    a := 5
    getType(&a) // output: is *int
    var aa *A
    getType(aa) // output: value is nil ; is *A
    getType(nil) // output: in is nil
}

func getType(in interface{}) {
    if in == nil {
        fmt.Println("in is nil")
        return
    }

    if reflect.TypeOf(in).Kind() != reflect.Ptr {
        fmt.Println("not ptr")
        return
    }

    if reflect.ValueOf(in).IsNil() {
        fmt.Println("value is nil")
    }

    if _, ok := in.(*int); ok {
        fmt.Println("is *int")
    }

    if _, ok := in.(*A); ok {
        fmt.Println("is *A")
    }
}

上面例子中,getType里面之所以一来就进行nil判断,是因为如果不把nil拦住的话,在执行下面的reflect.TypeOf(in).Kind()和reflect.ValueOf(in).IsNil()百分百panic。我们分别跟到reflect.TypeOf()和reflect.ValueOf()里面可以看到有这些定义:

// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {
    eface := *(*emptyInterface)(unsafe.Pointer(&i))
    return toType(eface.typ)
}

// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {
    if i == nil {
        return Value{}
    }

    // TODO: Maybe allow contents of a Value to live on the stack.
    // For now we make the contents always escape to the heap. It
    // makes life easier in a few places (see chanrecv/mapassign
    // comment below).
    escapes(i)

    return unpackEface(i)
}

我们在使用空的动态类型或者是空的动态值的时候,panic: runtime error: invalid memory address or nil pointer dereference出现常会遇到的无效地址的情况。而在使用IsNil()时也不是万能的,它只能判别指定的一些类型,否则直接panic:

// IsNil reports whether its argument v is nil. The argument must be
// a chan, func, interface, map, pointer, or slice value; if it is
// not, IsNil panics. Note that IsNil is not always equivalent to a
// regular comparison with nil in Go. For example, if v was created
// by calling ValueOf with an uninitialized interface variable i,
// i==nil will be true but v.IsNil will panic as v will be the zero
// Value.
func (v Value) IsNil() bool {
    ...
}

所以,上面的例子里面还应该加上recover来针对panic进行捕获,防止程序崩溃.

标签: golang interface
最后更新:2021年8月15日

PingD

反思让我成长

点赞
< 上一篇
下一篇 >

文章评论

取消回复

PingD

反思让我成长

归档
  • 2023年1月
  • 2022年3月
  • 2022年1月
  • 2021年10月
  • 2021年8月
  • 2021年4月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2019年9月
  • 2019年7月
  • 2019年6月
  • 2019年4月
  • 2019年3月
最新 热点 随机
最新 热点 随机
断更了,不想写了 新路由2(newifi d1) 小白刷老毛子固件 2021年度总结 golang之从源码角度看slice的len和cap 基于chan实现的简易协程池及说明 订单超时方案(初稿)
Go查看项目引用的包版本及当前最新的版本 Golang之HTTP EOF/connection reset by peer详解 sh、bash和zsh区别 golang之从源码角度看slice的len和cap 2021年度总结 Etcd raft 原理动画演示
最近评论

COPYRIGHT © 2021 dpjeep.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

蜀ICP备18036663号-1