淺談Golang中的接口值

golang中,接口值是由兩部分組成的,一部分是接口的類型,另外一部分是該類型對應的值,咱們稱其爲動態類型和動態值。golang

這個概念該如何理解呢?咱們先看一段代碼:bootstrap

var w io.Writer // type-<nil>
w = new(bytes.Buffer) // type-*bytes.Buffer
w = nil // type-<nil>

這裏先定義一個變量w,而後再爲其賦值,能夠看到,變量w的type都是不太同樣的,能夠用fmt%T來查看其動態類型。函數

fmt.Printf("%T\n",w)

在第一行定義變量w的時候,聲明瞭其類型爲io.Writer,這裏是真正意義上的空接口,爲何是空接口,就是它的類型和值都爲nil,在這裏能夠用==或者!=來和nil作判斷。指針

w == nil // return true

在第二行爲變量w賦值的時候,此時w的動態類型爲*bytes.Buffer,而後動態值是一個指向新分配的緩衝區的指針。code

package bytes

type Buffer struct {
    buf       []byte   // contents are the bytes buf[off : len(buf)]
    off       int      // read at &buf[off], write at &buf[len(buf)]
    bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
    lastRead  readOp   // last read operation, so that Unread* can work correctly.
}

此時就能夠調用Writer接口中的方法:接口

w.Write([]byte("ok"))

順便提一下,若是用第一行中的變量w來調用Write方法的話,程序會報錯,調用一個空接口值上的任意方法都會產生Panic
第三行爲w賦值的效果就和最初是同樣的了,動態類型和動態值都是nil,爲一個空接口。it

說到這裏,大概能明白接口值的意義了,不過還有一個問題,那就是一個接口爲空和一個接口包含空指針是不是一回事?咱們來看一段代碼:io

func test(w io.Writer)  {

    if w != nil{
        w.Write([]byte("ok"))
    }
}

func main() {

    var buf *bytes.Buffer
    test(buf)
}

若是執行這段程序,會報錯,咱們來稍微分析一下,在main()中,咱們首先聲明瞭一個buf變量,類型是*bytes.Buffer指針類型,在調用函數test()的時候,參數w會被賦值爲動態類型爲*bytes.Buffer,動態值爲nil,也就是w是一個包含了空指針值的非空接口。那麼在w != nil判斷時,這個等式即是成立的,不過這裏也從側面反映出一個現象,就是這種傳參都是值拷貝,那麼看到這裏,這段代碼也應該比較好修改了:ast

var buf io.Writer // buf = new(bytes.Buffer)

咱們再來看一段代碼:test

type Test interface {}

type Test1 interface {
    TestFunc()
}

type Structure struct {
    a int
}

func (s *Structure) TestFunc(){
    fmt.Println("Ok, Let's rock and roll!")
}

func fTest(t Test)  {
    fmt.Println(t == nil)
}

func fTest1(t1 Test1){
    fmt.Println(t1 == nil)
}

func fStructure(s *Structure){
    fmt.Println(s == nil)
}

func main() {
    var s *Structure = nil
    fTest(s) // false
    fTest1(s) // false
    fStructure(s) // true
    s.TestFunc() // Ok, Let's rock and roll!
}

執行一下代碼,是否和預期的結果同樣呢?Ok, Let's rock and roll!

相關文章
相關標籤/搜索