2017-05-18 65 views
0

我想獲得在訂閱結束時作爲PubNub消息傳遞的JSON值。這個代碼是接口轉換:接口{}是float64不是[]接口{} PubNub

package main 

import (
    "encoding/json" 
    "flag" 
    "fmt" 
    "github.com/pubnub/go/messaging" 
) 

type DeployMessages struct { 
    Server string 
    Repo string 
} 

type PNMessage struct { 
    Messages []DeployMessages 
    Id  string 
    Channel string 
} 

func main() { 
    publishKey := flag.String("pub", "demo", "publish key") 
    subscribeKey := flag.String("sub", "demo", "subscribe key") 

    channels := flag.String("channels", "channel1, channel2", "channels to subscribe to") 

    pubnub := messaging.NewPubnub(*publishKey, *subscribeKey, "", "", false, "", nil) 

    successChannel := make(chan []byte) 
    errorChannel := make(chan []byte) 

    go pubnub.Subscribe(*channels, "", successChannel, false, errorChannel) 

    subscribeHandler(successChannel, errorChannel, "Subscribe") 
} 

func (pnm *PNMessage) UnmarshalJSON(bs []byte) error { 
    var arr []interface{} 
    err := json.Unmarshal(bs, &arr) 
    if err != nil { 
     return err 
    } 
    messages := arr[0].([]interface{}) 
    pnm.Messages = make([]DeployMessages, len(messages)) 
    for i, m := range messages { 
     pnm.Messages[i].Server = m.(map[string]interface{})["server"].(string) 
     pnm.Messages[i].Repo = m.(map[string]interface{})["repo"].(string) 
    } 
    pnm.Id = arr[1].(string)  
    pnm.Channel = arr[2].(string) 
    return nil 
} 

func subscribeHandler(successChannel, errorChannel chan []byte, action string) { 

    for { 
     select { 
     case response, ok := <-successChannel: 
      if !ok { 
       break 
      } 
      if string(response) != "[]" { 
       message := PNMessage{} 
       err := json.Unmarshal([]byte(response), &message) 
       if err != nil { 
        break 
       } 
       fmt.Println(fmt.Sprintf("%s Response: %s ", action, response)) 
       fmt.Println("") 
      } 

     case failure, ok := <-errorChannel: 
      if !ok { 
       break 
      } 
      if string(failure) != "[]" { 
       if true { 
        fmt.Printf("%s Error Response: %s ", action, failure) 
        fmt.Println("") 
       } 
      } 

     case <-messaging.SubscribeTimeout(): 
      fmt.Printf("Subscirbe request timeout") 
     } 
    } 
} 

消息的格式是這樣的

[[{"Repo":"images","Server":"production"}], "149514560987662985", "channel1"]

這將引發以下恐慌

panic: interface conversion: interface {} is float64, not []interface {} [recovered] panic: interface conversion: interface {} is float64, not []interface {}

goroutine 1 [running]: encoding/json.(*decodeState).unmarshal.func1(0xc042065c20) C:/Go/src/encoding/json/decode.go:170 +0xf1 panic(0x6548e0, 0xc042009440) C:/Go/src/runtime/panic.go:489 +0x2dd main.(*PNMessage).UnmarshalJSON(0xc0420093c0, 0xc042009300, 0x3d, 0x40, 0x0, 0xb35198) C:/Users/olmadmin/Documents/work/Go/src/DeploymentServer/main.go:43 +0x499 encoding/json.(*decodeState).array(0xc04205b320, 0x64e6a0, 0xc0420093c0, 0x16) C:/Go/src/encoding/json/decode.go:489 +0xbe4 encoding/json.(*decodeState).value(0xc04205b320, 0x64e6a0, 0xc0420093c0, 0x16) C:/Go/src/encoding/json/decode.go:399 +0x28e encoding/json.(*decodeState).unmarshal(0xc04205b320, 0x64e6a0, 0xc0420093c0, 0x0, 0x0) C:/Go/src/encoding/json/decode.go:184 +0x221 encoding/json.Unmarshal(0xc042009300, 0x3d, 0x40, 0x64e6a0, 0xc0420093c0, 0xc042065c98, 0x5f82de) C:/Go/src/encoding/json/decode.go:104 +0x14f main.subscribeHandler(0xc042030c00, 0xc042030c60, 0x69c4a4, 0x9) C:/Users/olmadmin/Documents/work/Go/src/DeploymentServer/main.go:64 +0x222 main.main() C:/Users/olmadmin/Documents/work/Go/src/DeploymentServer/main.go:34 +0x27e

我引用這個問題的答案 https://stackoverflow.com/questions/29348262/decoding-pubnub-messages-with-golang-json 請指向正確的方向......?

回答

2

當輸入數據轉換爲[]interface{},這將是很長的之旅以達到原始數據類型。這裏是工作代碼:

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type DeployMessage struct { 
    Server string 
    Repo string 
} 

type PNMessage struct { 
    Messages []DeployMessage 
    Id  string 
    Channel string 
} 

// testing to marshal this json 
func main() { 
    // imagine if we have receive our data here. 
    data := []byte(`[[{"Repo":"images","Server":"production"}], "149514560987662985", "channel1"]`) 

    var getData []interface{} 
    err := json.Unmarshal(data, &getData) 
    if err != nil { 
     panic(err) 
    } 
    fmt.Printf("result getData = %+v\n", getData[0]) 

    getData2 := getData[0].([]interface{}) 
    fmt.Printf("result getData = %+v\n", getData2[0]) 

    getData3 := getData2[0].(map[string]interface{}) 

    var deployMessages []DeployMessage 
    deployMessages = append(deployMessages, DeployMessage{Server: getData3["Server"].(string), Repo: getData3["Repo"].(string)}) 

    pNMessage := PNMessage{ 
     Messages: deployMessages, 
     Id:  getData[1].(string), 
     Channel: getData[2].(string), 
    } 

    fmt.Printf("result = %+v\n", pNMessage) 

} 

上面的代碼將工作,但我不喜歡它。 https://play.golang.org/p/U6slzSgaxu

可以縮短代碼斷言你的數據是這樣的:

getData2 := getData[0].([]interface{})[0].(map[string]interface{}) 
repo := getData2["Repo"].(string) // this will get the value of Repo in string. 

最終輸出:

result = {Messages:[{Server:production Repo:images}] Id:149514560987662985 Channel:channel1} 
1

根據您粘貼恐慌的消息,錯誤似乎正在發生:

C:/Users/olmadmin/Documents/work/Go/src/DeploymentServer/main.go:43 

這似乎符合這一行:

messages := arr[0].([]interface{}) 

你似乎在期待那個位置的陣列來舉行另一個陣列,但顯然你在那裏得到一個float64,因此錯誤:

interface conversion: interface {} is float64, not []interface {} 

,您可以相應地由43行前添加此添加一些調試打印出你在這一點上得到的arr什麼,這樣你就可以斷言類型:

fmt.Printf("arr: %#v\n", arr) 
+0

是空輸出:ARR:[] – ozfive

+0

真奇怪。如果這是一個空數組,那麼下一行應該拋出一個「索引超出範圍」的錯誤,而不是float64錯誤。即使打印一個空數組,你是否始終得到float64錯誤?你的帖子中的行號是否與原始程序中的行號一致? – eugenioy