Go does not provide a built-in linked list type, so you must define your own struct to represent nodes and manually manage the pointers connecting them. The standard approach involves creating a Node struct with a Value and a Next pointer, then implementing methods to append or insert elements while updating these pointers.
Here is a practical implementation of a singly linked list with an Append method to add elements to the end:
package main
import "fmt"
// Node represents a single element in the linked list.
type Node struct {
Value int
Next *Node
}
// LinkedList represents the head of the list.
type LinkedList struct {
Head *Node
}
// Append adds a new node with the given value to the end of the list.
func (l *LinkedList) Append(value int) {
newNode := &Node{Value: value}
if l.Head == nil {
l.Head = newNode
return
}
current := l.Head
for current.Next != nil {
current = current.Next
}
current.Next = newNode
}
// Print traverses the list and prints values.
func (l *LinkedList) Print() {
for current := l.Head; current != nil; current = current.Next {
fmt.Printf("%d -> ", current.Value)
}
fmt.Println("nil")
}
func main() {
list := &LinkedList{}
list.Append(10)
list.Append(20)
list.Append(30)
list.Print()
}
If you need a doubly linked list or more complex operations (like deletion or insertion at specific indices), you can extend the Node struct to include a Prev pointer. However, for most standard use cases in Go, the container/list package is the preferred solution because it is optimized, handles memory management safely, and provides a doubly linked list out of the box.
Using container/list is generally safer and less error-prone than a manual implementation:
package main
import (
"container/list"
"fmt"
)
func main() {
l := list.New()
// Push back (append)
l.PushBack(10)
l.PushBack(20)
l.PushBack(30)
// Iterate
for e := l.Front(); e != nil; e = e.Next() {
fmt.Printf("%d -> ", e.Value)
}
fmt.Println("nil")
}
Choose the manual struct approach if you need to learn the underlying mechanics or require a custom node structure with specific metadata. Use container/list for production code where performance and reliability are priorities, as it avoids common pointer errors and handles edge cases like empty lists automatically.