在goroutine通道改变切片后,如何获得切片新索引?

时间:2015-12-16 23:33:32

标签: go

我想知道如何在切片中获取元素新索引,我有一个函数可以从数据库中获取应用程序,并查询某些(用于过滤),但是当我查询它们时,我得到了我不需要的,我试图从切片中删除它们,这样只有想要的才能进入视图。它正在工作,但我在goroutine中遇到索引的问题是较旧的索引,所以当它试图从切片中删除元素时它会发生恐慌:无论如何这里是我的代码:

// ListApplications will list the applications
func ListApplications(w http.ResponseWriter, r *http.Request) {
    session := common.Sesh(r)
    urlParse, err := url.ParseRequestURI(r.RequestURI)
    vals := urlParse.Query()

    if err != nil {
        log.Println(err)
    }
    if lvl, ok := session.Values["user_level"]; !ok || lvl.(int) < 3 {
        http.Redirect(w, r, "/", 401)
        return
    }

    db := common.Db()

    type UserResp struct {
        Action string
        I      int
        User   common.User
    }
    apps := []common.Application{}
    resp := make(chan UserResp)
    db.Order("accepted asc").Order("created_at asc").Find(&apps)
    var wg sync.WaitGroup
    for i, app := range apps {
        wg.Add(1)
        go func(i int, app common.Application) {
            user := common.User{}
            if vals.Get("class") != "" {
                db.Preload("Characters", "character_class = ?", vals.Get("class")).Model(&app).Related(&user)
                if len(user.Characters) == 0 {
                    resp <- UserResp{"remove", i, user}
                } else {
                    resp <- UserResp{"add", i, user}
                }
                wg.Done()
                return
            }

            db.Preload("Characters").Model(&app).Related(&user)
            log.Println(user)
            resp <- UserResp{"add", i, user}
            wg.Done()
        }(i, app)
    }

    go func() {
        wg.Wait()
        close(resp)
    }()

    for user := range resp {
        switch user.Action {
        case "add":
            apps[user.I].User = user.User
        case "remove":
        log.Println(len(apps), user.I)
            apps = append(apps[:user.I], apps[user.I+1:]...)
        }
    }

    common.View(w, r, "/application/list", &struct {
        Title string
        Apps  []common.Application
    }{"Viewing Applications", apps})
}

for user := range resp是我尝试在"remove"操作下删除的地方。但就像我说的那样,在频道上传递的索引有时会过时,所以如何在我的goroutines中保持持久索引

1 个答案:

答案 0 :(得分:2)

如果要从中移除元素,请不要range

而是通过索引遍历切片:

// Removes 2 from slice.
slice := []int{1,2,3}
for i := 0; i < len(slice); i++ {
    if slice[i] == 2 {
        slice = append(slice[:i], slice[i+1:]...)
        i--
    }
}
fmt.Println(slice) // [1 3]

关键是在删除当前元素后将索引光标向后移一(因此它不会前进)。