Go语言 嵌入式结构

3b6akqbq  于 2023-01-15  发布在  Go
关注(0)|答案(1)|浏览(169)

请问有没有人能解释一下下面的推送功能是如何工作的?
这是来自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]
2guxujil

2guxujil1#

Push函数的工作原理是,最初将head和tail设置为指向元素的同一指针。
后续调用将尾部元素的next字段设置为新元素指针。
Push在此处添加多个元素:

lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next //the tail becomes a new element with next as nil

关键是每次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。”

相关问题