请问有没有人能解释一下下面的推送功能是如何工作的?
这是来自https://gobyexample.com/generics的。
泛型方面对我来说是有意义的,但是我在List中的嵌入式struct元素上遇到了困难。
List似乎只有两个字段,它们是指向元素结构的指针。
查看Push中的逻辑,if语句似乎只遇到一次,即第一次调用方法Push时。
我不明白Push是如何在每次被调用时添加多个元素的。
package main
import "fmt"
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
type List[T any] struct {
head, tail *element[T]
}
type element[T any] struct {
next *element[T]
val T
}
func (lst *List[T]) Push(v T) {
if lst.tail == nil {
lst.head = &element[T]{val: v}
lst.tail = lst.head
} else {
lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next
}
}
func (lst *List[T]) GetAll() []T {
var elems []T
for e := lst.head; e != nil; e = e.next {
elems = append(elems, e.val)
}
return elems
}
func main() {
var m = map[int]string{1: "2", 2: "4", 4: "8"}
fmt.Println("keys:", MapKeys(m))
_ = MapKeys[int, string](m)
lst := List[int]{}
lst.Push(10)
lst.Push(13)
lst.Push(23)
fmt.Println("list:", lst.GetAll())
}
输出为:
keys: [2 4 1]
list: [10 13 23]
1条答案
按热度按时间2guxujil1#
Push函数的工作原理是,最初将head和tail设置为指向元素的同一指针。
后续调用将尾部元素的next字段设置为新元素指针。
Push在此处添加多个元素:
关键是每次next被赋值一个新元素,下面的代码行将tail设置为tail.next,这意味着每个'next'都指向下一个元素。
这就是单链表的概念--它允许单向遍历列表,从头开始,到尾结束,每个元素包含数据(在本例中为int)和指向下一个节点的指针(在本例中为element pointer),在最后一个元素中,next为nil,表示列表的结束。
这些列表比固定大小的数组内存效率更高,因为内存可以随着列表的增长而动态分配。
这是一位同事写来的,所以我不接受任何赞扬,但我认为这是一个很好的总结,所以把它放在这里,以防它对其他人有帮助:
......在else子句的第一行,tail指向“当前”tail的元素。所以它在这个元素上设置next。然后它改变tail是什么......但是这并不能撤销对之前是tail的元素的修改。
从头开始考虑,当没有元素时,head和tail是element 1,然后你按下(2),然后列表,tail将引用element 1,所以它将把element 1上的next设置为一个新元素2。
然后,它会设置列表的尾部指向element 2。”