获取未解组接口内的值

huangapple go评论82阅读模式
英文:

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:

  1. having my channel value be a generic and my listen & JSON decoder funcs (these are all put below) all return a generic or
  2. 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, &amp;testing, &amp;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{&quot;BTC/&quot; + stored_data.Base_currency, &quot;EOS/&quot; + stored_data.Base_currency}

	// create ws connections
	pubSocket, err := ws_client.ConnectToServer(&quot;public&quot;, 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, &amp;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
		}
	}()

	&lt;-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 &lt;- res
	}
	&lt;-ctx.Done()
	log.Println(&quot;closing public socket&quot;)
	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(&quot;unhandled response type: %T&quot;, c)
}

huangapple
  • 本文由 发表于 2022年6月13日 13:22:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/72598084.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定