Golang教程:结构体如何自我引用(来自官方maps教程)

Golang教程:结构体如何自我引用(来自官方maps教程) 正在学习来自 https://blog.golang.org/maps 关于映射的示例(代码如下)

我的问题:

  1. 我不理解这个结构体 Node… Next 如何能指向自身?
  2. 如何用数据初始化这个结构体??我甚至无法运行来检查它是如何工作的…

任何帮助都将不胜感激。谢谢!

package main
import "fmt"

func main() {
    type Node struct {
        Next  *Node
        Value interface{}
    }

    var first *Node
    visited := make(map[*Node]bool)

    for n := first; n != nil; n = n.Next {
        if visited[n] {
            fmt.Println("cycle detected")
            break
        }

        visited[n] = true
        fmt.Println("nada")
        fmt.Println(n.Value)
    }
}

更多关于Golang教程:结构体如何自我引用(来自官方maps教程)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

一个 Node 可以 指向另一个 Node

var third = &Node{nil, "3rd"}
var second = &Node{third, "2nd"}
var first = &Node{second, "1st"}

请注意,我是从最后一个没有 Next 节点的节点开始构造节点链的。

一个可运行的示例请参见 https://play.golang.org/p/epsTrOpVXnP

更多关于Golang教程:结构体如何自我引用(来自官方maps教程)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个关于结构体自引用和链表初始化的常见问题。让我直接解答:

1) 结构体如何自引用:

在Go中,结构体通过指针实现自引用。Next *Node 是一个指向 Node 类型的指针,而不是 Node 类型本身。这种设计避免了无限递归的内存分配,因为指针的大小是固定的(通常8字节),而结构体本身可能很大。

2) 如何初始化并运行:

你提供的代码缺少数据初始化。以下是完整的可运行示例:

package main

import "fmt"

func main() {
    type Node struct {
        Next  *Node
        Value interface{}
    }

    // 创建三个节点
    node3 := &Node{Value: "Third", Next: nil}
    node2 := &Node{Value: "Second", Next: node3}
    node1 := &Node{Value: "First", Next: node2}
    
    // 创建循环引用(用于检测循环)
    // node3.Next = node1 // 取消注释这行会创建循环

    var first *Node = node1
    visited := make(map[*Node]bool)

    for n := first; n != nil; n = n.Next {
        if visited[n] {
            fmt.Println("cycle detected")
            break
        }

        visited[n] = true
        fmt.Println(n.Value)
    }
}

更实用的链表初始化示例:

package main

import "fmt"

func main() {
    type Node struct {
        Next  *Node
        Value interface{}
    }

    // 方法1:直接初始化
    list := &Node{
        Value: "A",
        Next: &Node{
            Value: "B",
            Next: &Node{
                Value: "C",
                Next:  nil,
            },
        },
    }

    // 方法2:使用循环构建
    values := []string{"X", "Y", "Z"}
    var head *Node
    var current *Node
    
    for _, v := range values {
        newNode := &Node{Value: v, Next: nil}
        if head == nil {
            head = newNode
            current = head
        } else {
            current.Next = newNode
            current = newNode
        }
    }

    // 遍历链表
    for n := head; n != nil; n = n.Next {
        fmt.Printf("Value: %v, Next: %v\n", n.Value, n.Next)
    }
}

检测循环的完整示例:

package main

import "fmt"

func main() {
    type Node struct {
        Next  *Node
        Value interface{}
    }

    // 创建带循环的链表
    node1 := &Node{Value: 1}
    node2 := &Node{Value: 2}
    node3 := &Node{Value: 3}
    
    node1.Next = node2
    node2.Next = node3
    node3.Next = node1 // 创建循环

    visited := make(map[*Node]bool)
    
    for n := node1; n != nil; n = n.Next {
        if visited[n] {
            fmt.Printf("检测到循环在节点值: %v\n", n.Value)
            break
        }
        visited[n] = true
        fmt.Printf("访问节点值: %v\n", n.Value)
    }
}

运行这些代码会显示链表如何工作以及循环检测如何触发。结构体自引用是链表、树等数据结构的基础实现方式。

回到顶部