Golang教程:结构体如何自我引用(来自官方maps教程)
Golang教程:结构体如何自我引用(来自官方maps教程) 正在学习来自 https://blog.golang.org/maps 关于映射的示例(代码如下)
我的问题:
- 我不理解这个结构体 Node… Next 如何能指向自身?
- 如何用数据初始化这个结构体??我甚至无法运行来检查它是如何工作的…
任何帮助都将不胜感激。谢谢!
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 回复
这是一个关于结构体自引用和链表初始化的常见问题。让我直接解答:
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)
}
}
运行这些代码会显示链表如何工作以及循环检测如何触发。结构体自引用是链表、树等数据结构的基础实现方式。


