I am trying to iterate over nested loop as below
but the variables declared in first loop like varOne, varTwo, varThree do not get to the second loop
Matter of fact nothing works after the line for rowTwo := range rowsTwo {
Can anyone please point me to what am doing wrong or how to
func StudentScore() {
var appendedScores []interface{}
for rowOne := range rowsOne {
varOne := rowOne.FirstName
varTwo := rowOne.LastName
varThree := rowOne.UserName
req, _ := http.NewRequest("GET", fmt.Sprintf("https://example.com/users/%s/score", varThree), nil)
client := &http.Client{}
resp, _ := client.Do(req)
type responseData struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Score float64 `json:"score"`
}
type StudentData struct {
UserName string `json:"username_name"`
Score float64 `json:"score"`
}
var rowsTwo []responseData
respBody, _ := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(respBody, &rowsTwo)
fmt.Println("response: ", rowsTwo)
// var appendedScores []interface{}
studentData := &StudentData{}
for rowTwo := range rowsTwo {
fmt.Println("print vars from first loop: ", varOne, varTwo, varThree)
fmt.Println("api response: ", resp)
studentData.UserName=string(varThree)
studentData.Score=float64(rowTwo.Score)
appendedScores = append(appendedScores, *studentData)
}
}
fmt.Println("student scores: ", appendedScores)
}
Pretty much what am trying to do is use the values from the rows in the first range of rows and use to generate new values to use in the second for loop so i can have a final value to print. So the only reason for the 2 nested for loops is because i need values from first for loop
Is there something am missing or a better way to do this?
CodePudding user response:
type StudentScore struct {
UserName string `json:"user_name"`
Score float64 `json:"score"`
}
func GetStudentScore() ([]StudentScore, error) {
var scores []StudentScore
for _, row := range rowsOne {
s := StudentScore{UserName: row.UserName}
// request score data
resp, err := http.Get(fmt.Sprintf("https://example.com/users/%s/score", s.UserName))
if err != nil {
return nil, err
}
defer resp.Body.Close()
// unmarshal score data
var data struct {
Score float64 `json:"score"`
}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return nil, err
}
// set score field on Student instance
s.Score = data.Score
// append StudentScore
scores = append(scores, s)
}
return scores, nil
}
To do it concurrently you could do something like the following:
type StudentScore struct {
UserName string `json:"user_name"`
Score float64 `json:"score"`
}
func GetStudentScore() ([]StudentScore, error) {
var wg sync.WaitGroup
var ch = make(chan StudentScore)
for _, row := range rowsOne {
wg.Add(1)
// for each row execute the retrieveStudentScore in a separate goroutine
go func() {
if err := retrieveStudentScore(row.UserName, ch); err != nil {
log.Println("failed to retrieve StudentScore:", err)
}
wg.Done()
}()
}
go func() {
wg.Wait() // wait until every retrieveStudentScore is finished
close(ch) // this will cause the range loop below to exit
}()
var scores []StudentScore
for s := range ch {
// append StudentScore received from channel
scores = append(scores, s)
}
return scores, nil
}
func retrieveStudentScore(userName string, ch chan StudentScore) error {
// request score data
resp, err := http.Get(fmt.Sprintf("https://example.com/users/%s/score", userName))
if err != nil {
return err
}
defer resp.Body.Close()
// unmarshal score data
var data struct {
Score float64 `json:"score"`
}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return err
}
// send StudentScore to channel
ch <- StudentScore{UserName: userName, Score: data.Score}
return nil
}
