在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!