假设我有一个像这样的切片:
stu = [{"id":"001","name":"A"} {"id":"002", "name":"B"}]也许还有更多这样的元素。切片内部是一个长字符串,我想使用 json.unmarshal 来解析它。
type Student struct {
Id string `json:"id"`
Name string `json:"name"`
}
studentList := make([]Student,len(stu))
for i, st := range stu {
go func(st string){
studentList[i], err = getList(st)
if err != nil {
return ... //just example
}
}(st)
}
//and a function like this
func getList(stu string)(res Student, error){
var student Student
err := json.Unmarshal(([]byte)(stu), &student)
if err != nil {
return
}
return &student,nil
}
Run Code Online (Sandbox Code Playgroud)
我得到了 nil 结果,所以我想说 goroutine 是乱序执行的,所以我不知道它是否可以使用 StudentList[i] 来获取值。
以下是您的代码的一些潜在问题:
的值i可能不是您所期望的
for i, st := range stu {
go func(st string){
studentList[i], err = getList(st)
if err != nil {
return ... //just example
}
}(st)
}
Run Code Online (Sandbox Code Playgroud)
您启动了许多 goroutine,并在其中引用i. 问题是,i从启动 goroutine 的时间到 goroutine 引用它的时间(for 循环与它启动的 goroutine 同时运行)之间可能发生了变化。很可能在for任何 goroutine 之前完成,这意味着所有输出都将存储在最后一个元素中studentList(它们将相互覆盖,因此最终会得到一个值)。
一个简单的解决方案是传递i到 goroutine 函数(例如go func(st string, i int){}(st, i)(这会创建一个副本)。有关更多信息,请参阅此。
学生列表的输出
你没有在问题中说,但我怀疑你在循环完成fmt.Println(studentList[1]后立即运行(或类似)for。如上所述,很可能此时没有任何 goroutine 完成(或者它们可能完成,你不知道)。使用 aWaitGroup是解决这个问题的一个相当简单的方法:
var wg sync.WaitGroup
wg.Add(len(stu))
for i, st := range stu {
go func(st string, i int) {
var err error
studentList[i], err = getList(st)
if err != nil {
panic(err)
}
wg.Done()
}(st, i)
}
wg.Wait()
Run Code Online (Sandbox Code Playgroud)
我已经在操场上纠正了这些问题。