Having trouble with persistent data in struct due to pointer. How can I grab most recent instance of a struct with expected data?

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

Having trouble with persistent data in struct due to pointer. How can I grab most recent instance of a struct with expected data?

问题

我有一个微服务,通过API路径为用户准备数据。然而,在用户获取请求的数据之前,我需要进行一些数据处理。处理的方式如下:

我将一个填充了数据的结构体传递给两个处理函数getDataOriginWeather()getDataDestinationWeather()。在这两个函数都运行完之后,API服务器就可以供用户请求数据,也就是结构体。

问题是,用户获取的结构体中包含了经过这两个函数处理前后的混合记录。

结构体的预期数据应该只包含经过这两个函数处理后的数据。

我将这个结构体从一个包传递到另一个包。

以下是我的代码。

// 我正在使用的结构体,最终将由用户请求。
package models

type TravelItenaries struct {
	Origin                string
	Destination           string
	Flight_num            string
	Origin_latitude       string
	Origin_longitude      string
	Destination_latitude  string
	Destination_longitude string
	Coordinates_ori       string
	Coordinates_dest      string
	Temp_c_ori            string
	Temp_f_ori            string
	Temp_c_dest           string
	Temp_f_dest           string
	LastUpdated           string
}

以下是我处理数据的代码,然后才允许将其发送给用户。

package data

// 为了简洁起见,我省略了如何填充结构体的代码。我使用CSV文件进行填充。

func getDataOriginWeather() (travel *models.TravelItenaries, err error) {
	fmt.Println("从天气API获取起始数据...")
	// 构建天气API调用的URL参数。
	params := url.Values{
		"key": []string{"xxx"},
		"q":   []string{""},
	}

	// 构建请求的URL
	u := &url.URL{
		Scheme:   "https",
		Host:     "api.weatherapi.com",
		Path:     "/v1/current.json",
		RawQuery: params.Encode(),
	}

	client := &http.Client{}

	values := u.Query()
	var responseData models.OriginWeather
	for _, flight := range TravelItenaries {
		values.Set("q", flight.Coordinates_ori)
		u.RawQuery = values.Encode()
		req, err := http.NewRequest("GET", u.String(), nil)
		if err != nil {
			fmt.Println(err)
		}

		resp, err := client.Do(req)
		if err != nil {
			fmt.Println(err)
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Println(err)
		}

		json.Unmarshal(body, &responseData)
		flight.Temp_f_ori = strconv.FormatFloat(responseData.Current.Temp_f_ori, 'g', -1, 64)
		flight.Temp_c_ori = strconv.FormatFloat(responseData.Current.Temp_c_ori, 'g', -1, 64)
		flight.LastUpdated = responseData.Current.LastUpdated
		TravelItenaries = append(TravelItenaries, flight)
	}
	
	return travel, nil
}

// Run函数处理数据。
func Run() {
	fmt.Println("开始天气API请求...")
	getDataDestinationWeather() // 为了简洁起见,我不会在这里预设getDataDestinationWeather(),因为它与下面的函数基本相同
	getDataOriginWeather() // 这个函数和getDataDestinationWeather()在同一个结构体上工作。
	fmt.Println("完成天气API请求...\n...数据加载完毕,准备就绪。")
}

对我来说,问题是将这个结构体传递给handlers包时,结构体中包含了经过getDataDestinationWeather()getDataOriginWeather()处理之前的旧记录。

我希望能够明确地将经过data.Run()处理后的结构体传递给handlers.getWeather(),并且只包含处理后的数据。我在这里使用指针,但结果是混合的。

如果需要查看更多代码,请告诉我。

英文:

I have this microservice that prepares data for users to retrieve via API paths.

However, before users can get the requested data, I need to do some data processing. This is how I do it:

I pass a populated struct with data to two functions for processing getDataOriginWeather() and getDataDestinationWeather(). After both functions run, the API server becomes available for users to request data, aka the struct.

The issue is, the struct that users are pulling contains a mix of records from before and after the data has been processed through both functions.

The expected data for the struct should only be data after it's been passed through both functions.

I'm passing this struct from one package to another.

Here is my code.

// the struct I'm working with and that will eventually be get requested by users.
package models
type TravelItenaries struct {
Origin                string
Destination           string
Flight_num            string
Origin_latitude       string
Origin_longitude      string
Destination_latitude  string
Destination_longitude string
Coordinates_ori       string
Coordinates_dest      string
Temp_c_ori            string
Temp_f_ori            string
Temp_c_dest           string
Temp_f_dest           string
LastUpdated           string
}

Here is where I work with the data, before allowing it to be sent to the user.

package data
// for brevity I have removed how I populated the struct. I do so by using a CSV file. 
func getDataOriginWeather() (travel *models.TravelItenaries, err error) {
fmt.Println("Getting origin data from Weather API...")
// construct url params for weather API calls.
params := url.Values{
"key": []string{"xxx"},
"q":   []string{""},
}
// build URL for request
u := &url.URL{
Scheme: "https",
Host:   "api.weatherapi.com",
Path:   "/v1/current.json",
// encode params for URL syntax
RawQuery: params.Encode(),
}
client := &http.Client{}
values := u.Query()
var responseData models.OriginWeather
for _, flight := range TravelItenaries {
values.Set("q", flight.Coordinates_ori)
u.RawQuery = values.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
fmt.Println(err)
}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
json.Unmarshal(body, &responseData)
flight.Temp_f_ori = strconv.FormatFloat(responseData.Current.Temp_f_ori, 'g', -1, 64)
flight.Temp_c_ori = strconv.FormatFloat(responseData.Current.Temp_c_ori, 'g', -1, 64)
flight.LastUpdated = responseData.Current.LastUpdated
//fmt.Println(utils.PrettyPrint(flight))
TravelItenaries = append(TravelItenaries, flight)
}
return travel, nil
}
// Run processes the data for me.
func Run() {
fmt.Println("Starting Weather API requests...")
getDataDestinationWeather() // note that for brevity, I won't preset  getDataDestinationWeather() here because it's basically the exact same function as the one below
getDataOriginWeather() // this function and getDataDestinationWeather() work on the same struct. 
fmt.Println("Completed Weather API requests... \n...Data loaded & ready.")
}

The issue for me is passing this struct to my handlers package with the expected data after it's been processed by getDataDestinationWeather() and getDataOriginWeather()

package handlers 
// as you see I'm using a pointer, assuming my problems would be solved. 
// for the most part this does everything I want, except that I'm also getting 
// records in my struct from before it's been processed by getDataOriginWeather()
// and getDataDestinationWeather()
var Data = &data.TravelItenaries
func (s *Server) getWeather(w http.ResponseWriter, r *http.Request) {
...
// Here I'm simply trying to print the struct to the user after it's been processed
// by data.getDataOriginWeather() and data.getDataDestinationWeather with the expected 
// data. 
fmt.Println(utils.PrettyPrint(Data))
}

While var Data = &data.TravelItenaries does contain "expected data", it also contains old records from before the functions.

How can I explicitly pass the struct after it's been processed in the data.Run() to handlers.getWeather() with the processed data. My use of a pointer here is providing mixed results.

Please let me know if you need to see more of my code.

答案1

得分: 1

在"run"函数中,你似乎没有检查错误 - 我认为你应该检查错误。

  • 你正在处理一个可变的全局变量 - 如果不这样做,你的代码将更清晰、更易于测试和调试。

在数据被处理后,我如何明确地将结构体传递给handlers.getWeather(),并使用处理后的数据。我在这里使用指针提供了混合的结果。

创建一个包含处理调用所需内容的结构体。为该结构体实现http.Handler接口。在设置服务器时使用它。

示例:

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type TravelHandler struct {
	Data interface{} // 你需要提供http服务的预加载数据
}

func (th TravelHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	err := json.NewEncoder(w).Encode(th.Data)

	if err != nil {
		http.Error(w, "无法编码数据", 500)
	}
}

func createTravelHandler() *TravelHandler {
	// 填充旅行处理程序

	return &TravelHandler{}
}

func main() {
	th := createTravelHandler() // 没有可变的全局变量,从函数中返回处理程序(或通过多个函数传递它)

	err := http.ListenAndServe("localhost:3000", th)

	log.Println(err)
}
英文:

In the "run" function it seems you are:

  • not checking errors - I think you should.
  • working on a mutable global variable - your code will be cleaner and easier to test and debug if you do not.

> How can I explicitly pass the struct after it's been processed in the
> data.Run() to handlers.getWeather() with the processed data. My use of
> a pointer here is providing mixed results.

Create a struct that contains what is needed to process a call. Implement http.Handler for that struct. Use that when you set up your server.

Example:

package main
import (
"encoding/json"
"log"
"net/http"
)
type TravelHandler struct {
Data interface{} // the preloaded data you need to serve http
}
func (th TravelHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := json.NewEncoder(w).Encode(th.Data)
if err != nil {
http.Error(w, "could not encode data", 500)
}
}
func createTravelHandler() *TravelHandler {
// populate travel handler
return &TravelHandler{}
}
func main() {
th := createTravelHandler() // no mutable global, return the handler from a function (or pipe it through several functions)
err := http.ListenAndServe("localhost:3000", th)
log.Println(err)
}

huangapple
  • 本文由 发表于 2022年7月14日 05:19:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/72972742.html
匿名

发表评论

匿名网友

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

确定