英文:
How can I get a slices new index after a goroutine channel has mutated the slice?
问题
我想知道如何在切片中获取元素的新索引。我有一个从数据库中获取应用程序的函数,并查询特定的应用程序(用于过滤),但当我查询到不需要的应用程序时,我尝试从切片中删除它们,以便只有需要的应用程序显示在视图中。这个功能是有效的,但是我在goroutine中的索引出现了问题,它们是旧的索引,所以当它尝试从切片中删除元素时会出现错误。无论如何,这是我的代码:
// ListApplications将列出应用程序
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"
操作下删除元素。但正如我所说的,通过通道传递的索引有时是过时的,那么我该如何在goroutine中保持持久的索引呢?
英文:
I'm wondering how I can get an elements new index in a slice, I have a function that gets applications from a database, and queries for certain ones (for filtering) but when I query for ones and I get ones I don't need, I'm trying to remove them from the slice so that only the wanted ones make it to the view. It's working but I'm having a problem with the index's in the goroutines are the older index's so when it trys to remove the element from the slice it panics: Anyways here is my code:
// 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})
}
The for user := range resp
is where I'm trying to delete under the "remove"
action. But like I said, the index getting passed through on the channel is out dated sometimes so how can I maintain a persistent index in my goroutines
答案1
得分: 2
如果你想从切片中删除元素,请不要使用range
循环。
相反,可以通过索引循环遍历切片:
// 从切片中删除2。
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]
关键是在删除当前元素后,将索引光标向后移动一位(以防止向前移动)。
英文:
Don't range
over a slice if you want to remove elements from it.
Instead, loop over the slice by index:
// 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]
The point is bringing the index cursor back by one (so it won't go forward) after you've removed the current element.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论