Arrays 为什么围棋中很少使用列表?

Arrays 为什么围棋中很少使用列表?,arrays,list,go,Arrays,List,Go,我是新来的,对此很兴奋。但是,在我广泛使用的所有语言中:Delphi、C语言、C++、Python列表非常重要,因为它们可以动态地调整大小,而不是数组。 在Golang,确实有一个list.liststruct,但我很少看到关于它的文档——无论是在我的三本Go书籍中——Summerfield、Chisnal和Balbaert中——他们都在数组和切片上花费大量时间,然后跳到地图上。在源代码示例中,我还发现list.list几乎没有用处 与Python不同的是,Range在列表中不受支持,这是IMO

我是新来的,对此很兴奋。但是,在我广泛使用的所有语言中:Delphi、C语言、C++、Python列表非常重要,因为它们可以动态地调整大小,而不是数组。 在Golang,确实有一个
list.list
struct,但我很少看到关于它的文档——无论是在我的三本Go书籍中——Summerfield、Chisnal和Balbaert中——他们都在数组和切片上花费大量时间,然后跳到地图上。在源代码示例中,我还发现
list.list
几乎没有用处

与Python不同的是,
Range
在列表中不受支持,这是IMO的一大缺点。我是否遗漏了什么


切片当然不错,但它们仍然需要基于具有硬编码大小的数组。这就是列表的作用所在。是否有一种方法可以在Go中创建一个数组/切片,而无需硬编码数组大小?为什么列表被忽略了?

我认为这是因为关于它们没什么好说的,因为一旦你了解了处理泛型数据的主要习惯用法,容器/List包就不言自明了

在Delphi(没有泛型)或C语言中,您将在列表中存储指针或
TObject
s,然后在从列表中获取时将其转换回实际类型。在C++中,STL列表是模板,因此是由类型参数化的,而在C语言中(这些天)列表是通用的。 在Go中,
container/list
存储
interface{}
类型的值,这是一种特殊类型,能够通过存储一对指针来表示任何其他(实)类型的值:一个指针指向所包含值的类型信息,另一个指针指向该值(或者直接指向该值,如果其大小不大于指针的大小)。因此,当您想向列表中添加一个元素时,只需将其作为类型为
interface{}
accept values coo any类型的函数参数即可。但是,当您从列表中提取值,以及如何处理它们的实际类型时,您必须要么键入一个,要么对它们执行一个类型切换,这两种方法都是不同的,本质上是相同的

以下是一个例子:

在这里,我们使用
e.value()
获取元素的值,然后键入assert作为原始插入值的类型
int


您可以在“effectivego”或任何其他介绍书中阅读类型断言和类型切换。
container/list
包的文档总结了列表支持的所有方法。

注意,Go切片可以通过
append()
内置函数进行扩展。虽然这有时需要制作备份阵列的副本,但不会每次都这样,因为Go会使新阵列的大小过大,从而使其容量大于报告的长度。这意味着后续的追加操作可以在没有其他数据副本的情况下完成

虽然最终得到的数据副本比使用链表实现的等效代码多,但不需要单独分配列表中的元素,也不需要更新
Next
指针。对于许多用途,基于阵列的实现提供了更好或足够好的性能,因此这是语言中强调的。有趣的是,Python的标准
list
类型也是数组支持的,并且在附加值时具有类似的性能特征


也就是说,在某些情况下,链表是更好的选择(例如,当您需要从长列表的开始/中间插入或删除元素时),这就是为什么提供标准库实现的原因。我猜他们没有添加任何特殊的语言功能来使用它们,因为这些情况比使用切片的情况要少见。

当你想到列表时,几乎总是使用切片来代替Go。切片被动态地重新调整大小。它们的底层是可以改变大小的连续内存片

他们非常灵活,如果你读了这本书,你就会看到

以下是摘录:-

抄袭

b = make([]T, len(a))
copy(b, a) // or b = append([]T(nil), a...)
削减

a = append(a[:i], a[j:]...)
删除

a = append(a[:i], a[i+1:]...) // or a = a[:i+copy(a[i:], a[i+1:])]
删除而不保留顺序

a[i], a = a[len(a)-1], a[:len(a)-1]
流行音乐

x, a = a[len(a)-1], a[:len(a)-1]

a = append(a, x)

更新:这里有一个来自go团队本身的链接,它很好地解释了切片和数组以及切片内部结构之间的关系。

几个月前,当我第一次开始研究go时,我问了这个问题。从那时起,我每天都在阅读关于围棋的书籍,并用围棋进行编码

因为我没有得到这个问题的明确答案(尽管我接受了一个答案),我现在将根据我所学到的知识,自己回答这个问题,因为我问了这个问题:

有没有一种方法可以在Go中创建一个数组/切片,而无需硬编码 数组大小

对。切片不需要硬编码数组来从以下位置
切片

var sl []int = make([]int,len,cap)
此代码分配大小为
len
的片
sl
,容量为
cap
-
len
cap
是可在运行时分配的变量

为什么
list.list
被忽略

似乎主要原因是清单。清单在围棋中似乎很少受到关注,原因有:

  • 正如@Nick Craig Wood的回答中所解释的,有 实际上,对于无法完成的列表,什么都做不到 使用切片,通常效率更高,使用更清洁的 优雅的语法。例如,范围构造:

    for i:=range sl {
      sl[i]=i
    }
    
    无法与列表一起使用-循环需要C样式。而且 许多情况下,C++集合样式语法必须与列表一起使用:
    向后推

  • 也许更重要的是,
    list.list
    不是强类型的,它非常类似于Python的列表和字典,允许在集合中混合各种类型。这似乎与此相反 对事情采取积极的态度。围棋是一种非常典型的游戏
    for i:=range sl {
      sl[i]=i
    }
    
    It depends a lot on the number of elements in your lists, whether a true list or a slice will be more efficient when you need to do many deletions in the 'middle' of the list. #1 The more elements, the less attractive a slice becomes. #2 When the ordering of the elements isn't important, it is most efficient to use a slice and deleting an element by replacing it by the last element in the slice and reslicing the slice to shrink the len by 1 (as explained in the SliceTricks wiki)
    There are ways to mitigate the deletion problem --
    e.g. the swap trick you mentioned or
    just marking the elements as logically deleted.
    But it's impossible to mitigate the problem of slowness of walking linked lists.