如何正确使用嵌套的for循环在Golang中遍历行?

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

How do I properly use nested for loop to range over rows in golang?

问题

我正在尝试按照以下方式迭代嵌套循环,但是在第一个循环中声明的变量(如varOne,varTwo,varThree)无法传递到第二个循环中。

事实上,在for rowTwo := range rowsTwo {这一行之后,没有任何代码能够执行。

请问有人可以指出我做错了什么,或者如何改进吗?

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)

}

我想做的事情基本上是使用第一个循环中的行的值生成新的值,然后在第二个循环中使用这些新值,以便我可以得到最终要打印的值。所以嵌套的两个循环的唯一原因是我需要第一个循环中的值。

我是否遗漏了什么,或者有更好的方法来实现这个目标?

英文:

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?

答案1

得分: 1

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}

		// 请求分数数据
		resp, err := http.Get(fmt.Sprintf("https://example.com/users/%s/score", s.UserName))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		// 解析分数数据
		var data struct {
			Score float64 `json:"score"`
		}
		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
			return nil, err
		}

		// 设置学生实例的分数字段
		s.Score = data.Score

		// 添加学生分数
		scores = append(scores, s)
	}

	return scores, nil
}

要并发执行,你可以像下面这样做:

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)

		// 对于每一行,在单独的 goroutine 中执行 retrieveStudentScore 函数
		go func(row Row) {
			if err := retrieveStudentScore(row.UserName, ch); err != nil {
				log.Println("获取学生分数失败:", err)
			}
			wg.Done()
		}(row)
	}

	go func() {
		wg.Wait() // 等待所有 retrieveStudentScore 完成
		close(ch) // 这会导致下面的 range 循环退出
	}()

	var scores []StudentScore
	for s := range ch {
		// 从通道接收到的 StudentScore 添加到切片中
		scores = append(scores, s)
	}

	return scores, nil
}

func retrieveStudentScore(userName string, ch chan StudentScore) error {
	// 请求分数数据
	resp, err := http.Get(fmt.Sprintf("https://example.com/users/%s/score", userName))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// 解析分数数据
	var data struct {
		Score float64 `json:"score"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return err
	}

	// 将 StudentScore 发送到通道中
	ch <- StudentScore{UserName: userName, Score: data.Score}

	return nil
}
英文:
type StudentScore struct {
	UserName string  `json:&quot;user_name&quot;`
	Score    float64 `json:&quot;score&quot;`
}

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(&quot;https://example.com/users/%s/score&quot;, s.UserName))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		// unmarshal score data
		var data struct {
			Score float64 `json:&quot;score&quot;`
		}
		if err := json.NewDecoder(resp.Body).Decode(&amp;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:&quot;user_name&quot;`
	Score    float64 `json:&quot;score&quot;`
}

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(&quot;failed to retrieve StudentScore:&quot;, 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(&quot;https://example.com/users/%s/score&quot;, userName))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// unmarshal score data
	var data struct {
		Score float64 `json:&quot;score&quot;`
	}
	if err := json.NewDecoder(resp.Body).Decode(&amp;data); err != nil {
		return err
	}
	
	// send StudentScore to channel
	ch &lt;- StudentScore{UserName: userName, Score: data.Score}
	
	return nil
}

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

发表评论

匿名网友

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

确定