英文:
Getting values inside an unmarshalled interface
问题
我有一个WebSocket客户端,可以接收多种数据类型。一个函数将从服务器接收到的JSON解组为不同的结构体,具体取决于接收到的数据。然后,通过通道将该结构体作为接口返回给我的主文件。由于我从服务器接收到多种数据类型,无法指定解析函数的确切返回值。
在主文件中使用这些数据时,我希望能够遍历数据中的不同值。由于我返回的是一个接口,这似乎是不可能的。每当我尝试对接口进行索引时,都会收到一个错误,提示“c.VALUE未定义(类型interface{}没有VALUE字段或方法)”。
我觉得我在这里做错了什么。到目前为止,我想到的两个解决方案是:
1)让我的通道值成为一个泛型,并且我的监听和JSON解码函数(下面都有)都返回一个泛型,或者
2)创建一个带有方法的接口。我的通道将是这种类型,而我的监听和JSON解码函数将再次返回此接口。
不过,我不确定这两种方式是否能真正解决我的问题。我也不知道是否有一种方式在性能上比其他方式更好。
以下是我的代码,以更好地理解问题:
func main() {
// 检查是否处于生产或测试模式
var testing bool = true // 默认为测试模式
args := os.Args
isTesting(args, &testing, &stored_data.Base_currency)
// Go协程处理程序
comms := make(chan os.Signal, 1)
signal.Notify(comms, os.Interrupt, syscall.SIGTERM)
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var wg sync.WaitGroup
// 设置OHLC间隔和交易对
OHLCinterval := 5
pairs := []string{"BTC/" + stored_data.Base_currency, "EOS/" + stored_data.Base_currency}
// 创建WebSocket连接
pubSocket, err := ws_client.ConnectToServer("public", testing)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 创建WebSocket通道
pubCh := make(chan interface{})
defer close(pubCh)
// 监听WebSocket连接
wg.Add(1)
go pubSocket.PubListen(ctx, &wg, pubCh, testing)
// 连接到数据流
pubSocket.SubscribeToOHLC(pairs, OHLCinterval)
// 监听公共WebSocket
go func() {
for c := range pubCh {
fmt.Println(c) // 这是我希望能够更彻底地遍历数据的地方
}
}()
<-comms
cancel()
wg.Wait()
}
以下是PubListen函数和我的JSON解码函数中发生的情况:
func (socket *Socket) PubListen(ctx context.Context, wg *sync.WaitGroup, ch chan interface{}, testing bool) {
defer wg.Done()
defer socket.Close()
var res interface{}
socket.OnTextMessage = func(message string, socket Socket) {
res = pubJsonDecoder(message, testing)
ch <- res
}
<-ctx.Done()
log.Println("closing public socket")
return
}
func pubJsonDecoder(response string, testing bool) interface{} {
var resp interface{}
byteResponse := []byte(response)
resp, err := ohlcResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = heartBeatResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = serverConnectionStatusResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = ohlcSubscriptionResponseDecoder(byteResponse, testing)
}
}
}
return resp
}
感谢您提供的任何帮助。
英文:
I have a websocket client that receives multiple data types. A function unmarshals json received from the server into different structs depending on the data received. The struct is then returned as an interface through a channel to my main file. Since i receive multiple data types from the server, I am not able to specify the exact return value of my parsing function.
With the data in my main file, I would like to have a way to be able to then go through the different values in the data. Since I am returning an interface, this seems impossible to do. Whenever i try to index the interface, I receive an error saying c.VALUE undefined (type interface{} has no field or method VALUE)
.
I feel like I'm not doing something right here. The 2 solutions I've thought about so far are:
- having my channel value be a generic and my listen & JSON decoder funcs (these are all put below) all return a generic or
- create an interface with methods. My channel would be of this type and again, my listen & JSON decoder funcs would return this interface.
I'm not sure if either of these ways would actually solve my issue, though. I also don't know if there is one way that would be more performant compared to other ways.
Here is my code to better understand the issue
func main() {
// check if in production or testing mode
var testing bool = true // default to testing
args := os.Args
isTesting(args, &testing, &stored_data.Base_currency)
// go routine handler
comms := make(chan os.Signal, 1)
signal.Notify(comms, os.Interrupt, syscall.SIGTERM)
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var wg sync.WaitGroup
// set ohlc interval and pairs
OHLCinterval := 5
pairs := []string{"BTC/" + stored_data.Base_currency, "EOS/" + stored_data.Base_currency}
// create ws connections
pubSocket, err := ws_client.ConnectToServer("public", testing)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// create websocket channels
pubCh := make(chan interface{})
defer close(pubCh)
// listen to websocket connections
wg.Add(1)
go pubSocket.PubListen(ctx, &wg, pubCh, testing)
// connect to data streams
pubSocket.SubscribeToOHLC(pairs, OHLCinterval)
// listen to public socket
go func() {
for c := range pubCh {
fmt.Println(c) // This is where I would like to be able to go through my data more thoroughly
}
}()
<-comms
cancel()
wg.Wait()
}
Here is what happens in the PubListen function and my JSON decoding function
func (socket *Socket) PubListen(ctx context.Context, wg *sync.WaitGroup, ch chan interface{}, testing bool) {
defer wg.Done()
defer socket.Close()
var res interface{}
socket.OnTextMessage = func(message string, socket Socket) {
res = pubJsonDecoder(message, testing)
ch <- res
}
<-ctx.Done()
log.Println("closing public socket")
return
}
func pubJsonDecoder(response string, testing bool) interface{} {
var resp interface{}
byteResponse := []byte(response)
resp, err := ohlcResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = heartBeatResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = serverConnectionStatusResponseDecoder(byteResponse, testing)
if err != nil {
resp, err = ohlcSubscriptionResponseDecoder(byteResponse, testing)
}
}
}
return resp
}
Thanks for any help you may have
答案1
得分: 1
由于您似乎控制了可以进行反序列化的完整类型列表,您可以使用类型开关(type switch):
switch v := c.(type) {
case *ohlcResponse:
// 在此块中,v 是 *ohlcResponse 类型
case *heartBeatResponse:
// 在此块中,v 是 *heartBeatResponse 类型
case *serverConnectionStatusResponse:
// 在此块中,v 是 *serverConnectionStatusResponse 类型
case *ohlcSubscriptionResponse:
// 在此块中,v 是 *ohlcSubscriptionResponse 类型
default:
// 选择一种方式来报告未处理的类型:
log.Fatalf("未处理的响应类型:%T", c)
}
英文:
Since you seem to control the complete list of types which can be unesrialized, you can use a type swicth :
swich v := c.(type) {
case *ohlcResponse:
// in this block, v is a *ohlcRrsponse
case *heartBeatResponse:
// in this block, v is a *heartBeatResponse
case *serverConnectionStatusResponse:
// in this block, v is a *serverConnectionStatus
case *ohlcSubscriptionResponse:
// in this block, v is a *ohlcSubscriptionResponse
default:
// choose some way to report unhandled types:
log.Fatalf("unhandled response type: %T", c)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论