Привет народ. Последние несколько месяцев я пробовал играть на голанге, и учиться было довольно весело. Я делюсь фрагментом кода, реализующим связанный список.
Как мы все знаем, связанный список - это структура данных, которая содержит значение и указатель на следующее значение (или местоположение следующего значения). Связанный список может динамически расти, пока у вас не закончится место в куче. Схематично связанный список выглядит примерно так:
Теперь давайте посмотрим, как мы можем реализовать этот простой односвязный список в golang, где мы собираемся вставлять новые значения, а также печатать их.
type Node struct { Data int Next *Node }
Это очень распространенное определение узла. В первой строке указано, что Node
является типом данных, определяемым пользователем. Он содержит два поля Data
и Next
. Несколько вещей, которые нужно знать о структурах:
- Это составные типы данных.
- Может содержать значения разных типов.
- Эти значения известны как поля.
Теперь давайте посмотрим на добавление узла:
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
На этом пока все. Надеюсь, вам понравилось. Пожалуйста, не стесняйтесь оставлять комментарии к обзорам. Это поможет мне стать лучше.