golang积累-接口指针与结构体指针

from:https://blog.csdn.net/qq_26981997/article/details/52608081

对go做过开发的朋友都很熟悉interface。这几天在网上看到了篇文章,谈到了interface与nil判等的问题。题是好题,就进一步了解了一下。原题如下:Nil接口并不是有Nil指针的接口type Cat interface { Meow()}type Tabby struct {}func (*Tabby) Meow() { fmt.Println("meow") }func GetACat() Cat { var myTabby *Tabby = nil // Oops, we forgot to set myTabby to a real value return myTabby}func TestGetACat(t *testing.T) { if GetACat() == nil { t.Errorf("Forgot to return a real cat!") }} 毫无疑问,输出结果是空。也就是说GetACat()方法返回的值,不为nil。解答是“将一个指针返回了空指针”。说实话,真心没看懂!官方对interface的定义官方在常见问题中,对interface判断nil进行了描述:原文interface的内部实现,其实有两个很核心的元素,那就是type与value。interface==nil,仅当type、value均为nil,即(nil,nil)。很多时候,type有值,而value==nil,比如上题。实际开发中,不应存在type==nil,value!=nil的情况。 因此,原题的解答应该是:为type确定了类型指针,但value依然没有赋值。更多的疑问?查看了一些资料,有几个困惑,需要逐个分析: - 接口变量是否为指针类型? - 结构体指针能否与其接口变量判等?首先定义一个全局的接口和对应的两个实现类,便于后续的分析。//接口type Cat interface { Meow()}//实现类1type Tabby struct{}func (*Tabby) Meow() { fmt.Println("Tabby meow") }func GetNilTabbyCat() Cat { var myTabby *Tabby = nil return myTabby}func GetTabbyCat() Cat { var myTabby *Tabby = &Tabby{} return myTabby}//实现类2type Gafield struct{}func (*Gafield) Meow() { fmt.Println("Gafield meow") }func GetNilGafieldCat() Cat { var myGafield *Gafield = nil return myGafield}func GetGafieldCat() Cat { var myGafield *Gafield = &Gafield{} return myGafield} 接口变量是否为指针类型? 在面对类型时,可以利用反射包(reflect)的TypeOf获取的Type,再调用Kind来了解基础结构类别。 var ( cat2 = GetNilTabbyCat() ) fmt.Printf("cat1 information: type=%15v,kind=%10v \n",reflect.TypeOf(cat2),reflect.TypeOf(cat2).Kind())1234通过结果,我们可以知道,cat2是指针. 接口变量之间的判等 var ( cat1 Cat = nil cat2 = GetNilTabbyCat() cat3 = GetTabbyCat() cat4 = GetNilGafieldCat() ) fmt.Printf("cat1 information: nil?:%5v, type=%15v, value=%5v \n", cat1 == nil, reflect.TypeOf(cat1), reflect.ValueOf(cat1)) //接口变量,type、value都是nil,所以cat1==nil fmt.Printf("cat2 information: nil?:%5v, type=%15v, type.kind=%5v, value=%5v \n", cat2 == nil, reflect.TypeOf(cat2), reflect.TypeOf(cat2).Kind(), reflect.ValueOf(cat2)) //接口变量,type!=nil,所以cat2!==nil fmt.Printf("cat3 information: nil?:%5v, type=%15v, type.kind=%5v, value=%5v \n", cat3 == nil, reflect.TypeOf(cat3), reflect.TypeOf(cat3).Kind(), reflect.ValueOf(cat3)) //接口变量,type!=nil, 所以cat3!=nil fmt.Printf("cat4 information: nil?:%5v, type=%15v, type.kind=%5v, value=%5v \n", cat4 == nil, reflect.TypeOf(cat4), reflect.TypeOf(cat4).Kind(), reflect.ValueOf(cat4)) //接口变量, fmt.Printf("cat1==cat2?%5v , cat2==cat3?%5v, cat2==cat4?%5v \n", cat1 == cat2, cat2 == cat3, cat2 == cat4) //Output: //cat1 information: nil?: true, type=, value=//cat2 information: nil?:false, type= *main.Tabby, type.kind= ptr, value=//cat3 information: nil?:false, type= *main.Tabby, type.kind= ptr, value=&{} //cat4 information: nil?:false, type= *main.Gafield, type.kind= ptr, value=//cat1==cat2?false , cat2==cat3?false, cat2==cat4?false 从运行结果看,接口变量之间判断,是要比较type和value的。cat1的type是空,所以cat1!=cat2。cat2与cat3的值不同,所以不等。cat2与cat4的type不同,所以不等。 更进一步,其实可以使用unsafe.Pointer来了解,可以很清楚的了解cat2变量的类别和值的情况,代码如下:type iface struct { itype uintptr ivalue uintptr }d1 := (*iface)(unsafe.Pointer(&cat1))d2 := (*iface)(unsafe.Pointer(&cat2))d3 := (*iface)(unsafe.Pointer(&cat3))d4 := (*iface)(unsafe.Pointer(&cat4))fmt.Println(d1)fmt.Println(d2)fmt.Println(d3)fmt.Println(d4)//Output://&{0 0} //&{7024192 0} //&{7024192 7302976} //&{7024128 0} 接口变量能否与其结构体指针判等 从前面代码对比可以知道,接口变量是指针。那接口指针是否会与结构体指针相同呢? type iface struct { itype uintptr ivalue uintptr } var ( cat1 Cat = GetNilTabbyCat() //接口指针 cat2 = GetTabbyCat() //接口指针 cat3 *Tabby = &Tabby{} //结构体指针 ) d1 := (*iface)(unsafe.Pointer(&cat1)) d2 := (*iface)(unsafe.Pointer(&cat2)) d3 := (*iface)(unsafe.Pointer(&cat3)) fmt.Printf("cat1 information: nil?:%5v, type=%15v, value=%v ,%v \n", cat1 == nil, reflect.TypeOf(cat1), reflect.ValueOf(cat1), d1) //接口变量,type、value都是nil,所以cat1==nil fmt.Printf("cat2 information: nil?:%5v, type=%15v, type.kind=%10v, value=%v ,%v \n", cat1 == nil, reflect.TypeOf(cat2), reflect.TypeOf(cat2).Kind(), reflect.ValueOf(cat2), d2) //接口变量,type!=nil,所以cat2!==nil fmt.Printf("cat3 information: nil?:%5v, type=%15v, type.kind=%10v, value=%v ,%v \n", cat3 == nil, reflect.TypeOf(cat3), reflect.TypeOf(cat3).Kind(), reflect.ValueOf(cat3), d3) //接口变量,type!=nil, 所以cat3!=nil fmt.Printf("cat1==cat2?:%5v, cat2==cat3?%v \n", cat1==cat2,cat2==cat3 ) //Output: //cat1 information: nil?:false, type= *main.Tabby, value= ,&{7024192 0}

    //cat2 information: nil?:false, type=    *main.Tabby, type.kind=      ptr, value=&{} ,&{7024192 7302976}

    //cat3 information: nil?:false, type=    *main.Tabby, type.kind=      ptr, value=&{} ,&{7302976 0}

    //cat1==cat2?:false, cat2==cat3?true

可以看出,结构体指针是可以与接口指针进行判等的,但要注意,尽管cat2、cat3的ivalue指向的地址不同,但比较的是具体的值,所以相等。

简单结论:

指针的判断,都涉及到type和value。

接口指针之间的判等,要基于type与value,一个不同则不等。

接口指针与其对应实现的结构体指针,可以进行判等操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容