遍历列表以删除元素会跳过某些元素,而另一些则翻倍

问题描述 投票:0回答:1

这是我遇到问题的功能:

func pruneattackoptions(currplayer int) (newoptions []string) {

    if currplayer == 0 {
        newoptions := make([]string, len(options))
        copy(newoptions, options)
        for i, y := range options {
            c, d := parseposition(y)
            fmt.Println(y)
            fmt.Println(string(board[c][d]))
            if string(board[c][d]) == "_" || unicode.IsLower(rune(board[c][d])) {
                newoptions = append(options[:i], options[i+1:]...)
            }
        }
    }

    if currplayer == 1 {

        for i, y := range options {
            c, d := parseposition(y)

            if string(board[c][d]) == "_" || unicode.IsUpper(rune(board[c][d])) {
                newoptions = append(options[:i], options[i+1:]...)
            }
        }
    }
    return newoptions
}

这基本上是一个国际象棋游戏,我试图在游戏开始时删除白人球员的所有不可行选择,白人是大写字母,黑人是小写字母。

问题是,当我运行程序时,它不仅完全跳过了某些选项中的值,例如“ A4”,实际上还向新选项列表中添加了100个“ H8”副本,这是为什么发生的,我该如何解决它吗?

go iteration slice
1个回答
0
投票

函数append不保证将结果放入存储器的新区域。考虑以下代码:

package main

import (
    "fmt"
)

func main() {
        s0 := []string{"a", "b", "c", "d", "e", "f"}

        // suppose I want to delete "c":
        s1 := append(s0[:2], s0[3:]...)

        // the last element in s0 was duplicated:
        fmt.Printf("s0=%v\ns1=%v\n", s0, s1)

        // you can see that s0 and s1 point to the same memory:
        fmt.Printf("addr s0=%v\naddr s1=%v\n", &s0[0], &s1[0])
}

输出:

s0=[a b d e f f]
s1=[a b d e f]
addr s0=0xc000104120
addr s1=0xc000104120

如您所见,append只是将“ c”之后的所有元素向左移动1。它在s0使用的同一内存中进行了移动。这就是为什么“ f”被复制的原因。现在s0s1都指向相同的内存,但是s1短了1个元素。

正确的方法是有条件地附加元素,如下所示:

func removeC(options []string) (newoptions []string) {
  newoptions = make([]string, 0, len(options))
  for _, opt := range options {
    if opt != "c" {
      newoptions = append(newoptions, opt)
    }
  }
  return
}

不是我make包含0个元素的新切片,但保留的内存足以容纳len(options)个元素。这不是必需的,但是它将避免在append函数内部进行不必要的分配。

© www.soinside.com 2019 - 2024. All rights reserved.