liveBook · Manning

Linked list

As explained in Go in Action, Second Edition

A linked list is a sequence data structure whose elements are stored in nodes connected by links and whose element type can be parameterized in its generic form.

A linked list stores a sequence in nodes rather than in contiguous memory. Each node holds a value and a pointer to the next node. Insertion or removal can relink nodes without shifting other elements, though reaching an indexed position requires following links. Go slices remain the simpler choice for most production uses. section 6.1 section 6.3

Listing 6.1 A generic node implementation
type node[T any] struct { #1
	value T #2
	next  *node[T] #3
}

A type parameter keeps the stored value and the next node the same type: node[T any] holds value T and next *node[T]. section 6.1

The list keeps a head pointer and a size. Its concrete type uses T comparable so operations such as Remove and Contains can test values for equality. This is narrower than a generic List[T any] interface: a LinkedList can implement that interface for types permitted by its comparable constraint. section 6.1 section 6.3

Listing 6.12 Defining a generic List interface
type List[T any] interface {
	Collection[T]
	Get(index int) (T, error)
	Set(index int, item T) error
	Insert(index int, item T) error
	RemoveAt(index int) (T, error)
}

The List interface combines collection operations with indexed Get, Set, Insert, and RemoveAt methods. It defines what callers can do without requiring them to use a linked-list implementation. section 6.3

Adding an item walks to the tail and links a new node, or sets the head if the list is empty. Removing a matching item links the preceding node to the following one; removing the head changes the head pointer instead. Both changes update the stored size. section 6.3

Listing 6.16 Finishing the interface implementation
func (l *LinkedList[T]) Set(index int, item T) error {
	if index < 0 || index >= l.size {                #1
		return errors.New("index out of bounds")
	}
	curr := l.head
	for i := 0; i < index; i++ {                     #2
		curr = curr.next
	}
	curr.value = item                                #3
	return nil
}

func (l *LinkedList[T]) Insert(index int, item T) error {
	if index < 0 || index > l.size {                 #4
		return errors.New("index out of bounds")
	}
	n := &node[T]{value: item}                       #5
	if index == 0 {                                  #6
		n.next = l.head
		l.head = n
	} else {
		curr := l.head
		for i := 0; i < index-1; i++ {               #7
			curr = curr.next
		}
		n.next = curr.next                           #8
		curr.next = n
	}
	l.size++                                         #9
	return nil
}

func (l *LinkedList[T]) RemoveAt(index int) (T, error) {
	var zero T
	if index < 0 || index >= l.size {                #10
		return zero, errors.New("index out of bounds")
	}
	var prev *node[T]
	curr := l.head
	for i := 0; i < index; i++ {                     #11
		prev = curr
		curr = curr.next
	}
	if prev == nil {                                 #12
		l.head = curr.next
	} else {
		prev.next = curr.next                        #13
	}
	l.size--                                         #14
	return curr.value, nil
}

Insert checks the index, handles insertion at the head, or walks to the preceding node before changing links. Set also walks from the head and reports an out-of-bounds index. section 6.3

Using a typed list

A LinkedList[int] can hold 10, 20, and 30; Insert(1, 15) places a value between the first two items. The same list can then be read with Get, changed with Set, and shortened with RemoveAt. section 6.3

How Go in Action, Second Edition covers it

How deep it goes
Works through nodes, interface methods, traversal, pointer updates, and bounds checks; treats production use as uncommon beside slices.
Examples
Demonstrates an integer list with Add, Insert, Get, Set, and RemoveAt, plus a generic list-reversal function.
What it assumes
Assumes familiarity with Go structs, pointers, and interfaces while introducing type parameters through a generic node.
What you can do after
Build it from scratch as a typed Go collection with linked nodes, indexed operations, and a generic interface.
How it connects
Connects linked lists to Go generics, type constraints, generic interfaces, pointers, and slices.

Also explained in

Compare how 8 books explain linked list →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Action, Second Edition. The section links point to the parts of the book it draws on.