简体   繁体   中英

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

I am trying to get at the JSON values that are passed as a PubNub message on the subscribe end. the code for this is

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")
        }
    }
}

The format of the message is this

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

This throws the following panic

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

I was referencing the answer to this question https://stackoverflow.com/questions/29348262/decoding-pubnub-messages-with-golang-json Please point me in the right direction...?

When converting incoming data to []interface{} , this is going to be long journey to get to the original data type. Here is the working code :

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)

}

Above code will works but I don't like it. https://play.golang.org/p/U6slzSgaxu

You can shorten the code the assert your data like this :

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

final output :

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

According to the panic message you pasted, error seems to be occurring in:

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

Which seems to correspond to this line:

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

You seem to be expecting that position to the array to hold another array, but apparently you are getting a float64 there, and thus the error:

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

You can add some debugging to print out what you are getting in arr at that point, so that you can then assert the type accordingly by adding this before that line 43:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM