Arrays 为什么围棋中很少使用列表?
我是新来的,对此很兴奋。但是,在我广泛使用的所有语言中:Delphi、C语言、C++、Python列表非常重要,因为它们可以动态地调整大小,而不是数组。 在Golang,确实有一个Arrays 为什么围棋中很少使用列表?,arrays,list,go,Arrays,List,Go,我是新来的,对此很兴奋。但是,在我广泛使用的所有语言中:Delphi、C语言、C++、Python列表非常重要,因为它们可以动态地调整大小,而不是数组。 在Golang,确实有一个list.liststruct,但我很少看到关于它的文档——无论是在我的三本Go书籍中——Summerfield、Chisnal和Balbaert中——他们都在数组和切片上花费大量时间,然后跳到地图上。在源代码示例中,我还发现list.list几乎没有用处 与Python不同的是,Range在列表中不受支持,这是IMO
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的回答中所解释的,有
实际上,对于无法完成的列表,什么都做不到
使用切片,通常效率更高,使用更清洁的
优雅的语法。例如,范围构造:
无法与列表一起使用-循环需要C样式。而且 许多情况下,C++集合样式语法必须与列表一起使用:for i:=range sl { sl[i]=i }
等向后推
- 也许更重要的是,
不是强类型的,它非常类似于Python的列表和字典,允许在集合中混合各种类型。这似乎与此相反 对事情采取积极的态度。围棋是一种非常典型的游戏list.list
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)for i:=range sl { sl[i]=i }
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.