2016-05-08 121 views
1

爲什麼第一個例子失敗了,但第二個順利呢?類型斷言和接口

做這種斷言的正確方法是什麼?

例1 https://play.golang.org/p/4LRGQLdGPB

// example 1 
type Packet map[string]interface{} 

func get(pack interface{}) { 
    if packet, ok := pack.(Packet); !ok { 
     fmt.Printf("error: %#v, %#v\n", pack, packet) 
    } 
} 

func main() { 
    pack := make(map[string]interface{}) 
    pack["qwe"] = 123 
    get(pack) 
} 

// error: map[string]interface {}{"qwe":123}, main.Packet(nil) 

例2 https://play.golang.org/p/Pd9jvvNrq5

// example 2 
type Packet map[string]interface{} 

func get(pack interface{}) { 
    var p Packet 
    if packet, ok := pack.(map[string]interface{}); !ok { 
     fmt.Printf("%#v, %#v\n", pack, packet) 
    } else { 
     p = packet 
    } 
    fmt.Printf("%#v\n", p) 
} 

func main() { 
    pack := make(map[string]interface{}) 
    pack["qwe"] = 123 
    get(pack) 
} 

// main.Packet{"qwe":123} 

回答

1

是你不傳遞Packet,你傳遞一個map[string]interface{},這是一種完全不同類型的問題就Go而言。

如果您使用pack := make(Packet)pack := Packet{},它將按預期工作。

playground

+0

也可以通過更換GET(包)來完成(包(包) ) – Apin

+0

@Apin真的,但它真的毫無意義 – OneOfOne

0

的回答和評論到目前爲止被誤解,混淆,或至少刷牙了很多細節在type assertiontype conversion之間的區別。

語法thing.(AType)是一個類型斷言。將在運行時評估。用於當這將是成功的標準(即ok == true)可以被歸結爲真2情況:

  1. thing是字面上AType類型。不是像你的Packet重新宣佈的類型。
  2. AType是一個接口,並且thing滿足接口。

在其他情況下,okfalse(或者如果使用單值版本foo := bar.(Baz)foo將是任何適當的零值)。

語法AType(thing)是一種類型轉換。將在編譯時評估。類型轉換要求內存結構爲AType,無論類型thing是相同的。

因此,在你的榜樣類型斷言,packet, ok := pack.(Packet)導致ok == false因爲Packet是一個非接口類型,packet是不是字面上的那種類型的,它是map[string]interface類型。

但是,你可以做類型轉換Packet(pack),因爲類型Packet和變量pack具有相同的底層存儲結構,map[string]interface{}

+0

** 1。如果我有'var p interface {} = int(123)''那麼我可以寫'p。(int)'所以,規則是**東西是一個接口,持有類型AType **,不是嗎? – Exel

+0

「如果我有var p接口{} = int(123)那麼我可以寫p。(int)所以,規則是一個接口,保存類型AType「是我的一個特例。在這個例子中,雖然'p'被聲明爲'interface {}',但底層數據的字面類型'int'。但是如果你定義了'type Foo int',你會發現'p。(Foo)'失敗,因爲'p'的基礎數據不是'Foo'類型。 – Endophage

+0

這可能有助於思考接口類型爲元組,它們引用2條信息:底層結構的類型和結構數據本身。 – Endophage