Привет народ. Последние несколько месяцев я пробовал играть на голанге, и учиться было довольно весело. Я делюсь фрагментом кода, реализующим связанный список.

Как мы все знаем, связанный список - это структура данных, которая содержит значение и указатель на следующее значение (или местоположение следующего значения). Связанный список может динамически расти, пока у вас не закончится место в куче. Схематично связанный список выглядит примерно так:

Теперь давайте посмотрим, как мы можем реализовать этот простой односвязный список в golang, где мы собираемся вставлять новые значения, а также печатать их.

type Node struct {
 Data int
 Next *Node
}

Это очень распространенное определение узла. В первой строке указано, что Node является типом данных, определяемым пользователем. Он содержит два поля Data и Next. Несколько вещей, которые нужно знать о структурах:

  1. Это составные типы данных.
  2. Может содержать значения разных типов.
  3. Эти значения известны как поля.

Теперь давайте посмотрим на добавление узла:

func (n *Node) AddNode(data int) {
 newNode := Node{data, nil}
 iter := n
 for iter.Next != nil {
  iter = iter.Next
 }
 iter.Next = &newNode
}

Первая строка объявляет функцию AddNode как тип *Node. n *Node известен как получатель. AddNode принимает аргумент типа int. newNode := Node{data, nil} определяет переменную newNode типа Node и инициализируется двумя значениями: data и nil. Следующие 4 строки находят подходящее место для newNode объекта в связанном списке и помещают его туда.

Объявляя AddNode с помощью получателя n *Node, мы гарантируем, что AddNode может быть вызван только с использованием переменной типа *Node. Проще говоря, это стиль определения функции-члена в golang.

Давайте посмотрим, как мы можем отображать значения:

func (n *Node) PrintNode() {
 iter := n
 for iter != nil {
  fmt.Println(iter.Data)
  iter = iter.Next
 }
}

Мы заявили PrintNode с n *Node приемником. Он выполняет итерацию Node, на которую указывает n, печатая каждый Data. Давайте теперь посмотрим на основной метод:

func main() {
 newNode := Node{10, nil}
 newNode.AddNode(20)
 newNode.AddNode(30)
 newNode.AddNode(40)
 newNode.PrintNode()
}

Как мы видим, AddNode и PrintNode должны вызываться с использованием переменной (или получателя) типа Node. Если мы попытаемся вызвать AddNode без какого-либо получателя, это приведет к ошибке ниже:

func main() {
 newNode := Node{10, nil}
 newNode.AddNode(20)
 newNode.AddNode(30)
 newNode.AddNode(40)
 AddNode(10) //Will result in compilation error
 newNode.PrintNode()
}
go build -o linkedlist.out linkedlist.go
./linkedlist.go:34:2: undefined: AddNode

Полный код доступен здесь https://gist.github.com/sandeep-sarkar/dc6a04884638f04dda9f852e7735cae9

На этом пока все. Надеюсь, вам понравилось. Пожалуйста, не стесняйтесь оставлять комментарии к обзорам. Это поможет мне стать лучше.