接口可以是 nil 类型,但这并不意味着它们是 nil?

我写了一些代码,实际上就是这样做的:


package main


import "fmt"


type SomeInterface interface {

    Retrieve(identifier string)

}


type SomeStruct struct {}


func (r SomeStruct) Retrieve(identifier string) {

    fmt.Println("identifier ", identifier)

}


type Handler struct {

    Name string

    SomeObject SomeInterface

}


func main() {

    var someStruct *SomeStruct

    var h = Handler{

        Name: "helo",

        SomeObject: someStruct,

    }

    fmt.Printf("before %+v\r\n", h.SomeObject)

    if h.SomeObject == nil {

        fmt.Printf("during %+v\r\n", h.SomeObject)

    }

    fmt.Printf("after %+v\r\n", h.SomeObject)

}

请有人向我解释为什么上面的输出是:


before <nil>

after <nil>

我一直在阅读有关类型的接口的信息,但在这种情况下,我将接口分配给了一个尚未分配的指针,因此我本来以为该接口并且我会看到 - 唉,事实并非如此。nil== nilduring <nil>


绝地无双
浏览 158回答 3
3回答

凤凰求蛊

接口值是一个简单的数据结构,由两部分组成:类型和基础值。因此,接口值本身可以是 ,或者接口值可以存在,但基础值可以是 。例如:nilnilvar x interface{} = nil // x is nilvar y interface{} = (interface{})(nil) // y is a interface{}, which *contains* nil这在某些概念上与此差异相似:var x []*int = nil // x is nilvar y []*int = []*int{nil} // y is a []*int, which *contains* nilfmt.Printf由于接口格式化输出的方式,掩盖了接口情况下的差异;如果您愿意,可以使用反射更清楚地看到差异。

眼眸繁星

在 Go 中,引用某些接口的实现者的变量可以具有多种类型。它可以是类型(是的,可以描述类型以及值),它可以是其实现者之一的类型,也可以是指向其实现者之一的指针的类型。默认情况下,引用接口的变量的类型为 。一旦你向它分配了一些东西(除了它本身),它就会采用你分配给它的东西的类型(同样,要么是它的实现者之一的类型,要么是指向其中一种类型的指针)。<nil>nilnilnil可以使用 打印接口变量的类型,并使用 %v 打印其值:%Tfunc main() {&nbsp; &nbsp; var i SomeInterface&nbsp; &nbsp; fmt.Printf("%T, %v\n", i, i) // Prints <nil>, <nil>&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; var someStruct SomeStruct&nbsp; &nbsp; i = someStruct&nbsp; &nbsp; fmt.Printf("%T, %v\n", i, i) // Prints main.SomeStruct, {}&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; var someStructPtr *SomeStruct&nbsp; &nbsp; i = someStructPtr&nbsp; &nbsp; fmt.Printf("%T, %v\n", i, i) // Prints *main.SomeStruct, <nil>}现在,每当您比较时,只有当两个操作数的类型和值都匹配时,比较才会被计算为 true。在你的情况下,的值显然是(毕竟,的值肯定是 ,并且你将其值存储在 中)。的类型,根据我刚才解释的内容,必须是 。的价值显然是。h.SomeObject == nilh.SomeObject<nil>someStruct<nil>h.SomeObjecth.SomeObject*SomeStructnil<nil>但是,是什么类型?nil好吧,可以采用多种类型,编译器必须决定每种用法应该采用哪种类型。当涉及到比较和分配时,它只是简单地采用它被比较或分配的东西的类型。例如,如果要将整数指针与 进行比较,则在这种情况下,类型为 。nilnilnil*int但所有这些都必须在编译时决定,并且引用接口的变量可以在运行时更改类型。那么,当您将引用接口的变量与 进行比较时,在这种情况下,编译器会为操作数提供什么类型呢?好吧,它给了它唯一合理的类型, .nilnil<nil>最后一个示例,请考虑以下代码:func main() {&nbsp; &nbsp; var p *SomeStruct = nil // = nil is optional; pointers default to nil&nbsp; &nbsp; var i SomeInterface = p&nbsp; &nbsp; printf("%t\n", p == nil) // Prints true&nbsp; &nbsp; printf("%t\n", p == i) // Prints true&nbsp; &nbsp; printf("%t\n", i == nil) // Prints false}p == nil为 true,因为 is 的类型带有值 ,并且(在本例中)也是具有值的类型。p*SomeStruct<nil>nil*SomeStruct<nil>p == i是 true,因为 也是具有值的类型(它只是存储 的类型和值)。i*SomeStruct<nil>p但是,是 false,因为在这种情况下,采用的类型而不是 。i == nilnil<nil>*SomeStruct解决这个问题的方法是永远不要在接口引用变量中存储一些有价值的东西,除了它本身。这样,每当接口引用变量的值为 时,其类型也将是 ,并且比较将按预期工作。因此,您经常会看到如下所示的代码:<nil>nil<nil><nil>nilif p == nil {&nbsp; &nbsp; i = nil} else {&nbsp; &nbsp; i = p}

aluckdog

SomeObject 不是 nil,它只是指向 SomeStruct,它是 nil。我认为混乱是fmt。Printf打印这种情况,因为它遵循指针,最终结果是零。<nil>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go