# golang container package

By [Primrose](https://paragraph.com/@primrose) · 2023-06-12

---

container package
=================

golang에는 빌트인으로 사용할 수 있는 container package가 있다.

개발을 하다보면, 자료구조를 사용할 일이 꽤 생긴다.

go에서는 container 패키지에서 기본 자료구조를 제공해주므로 꽤나 편리하게 사용할 수 있다.

패키지에서 제공하는 자료구조는 다음과 같다.

*   Linked list
    
*   Heap
    
*   Ring (Circular list)
    

container 패키지를 이용해서 간단한 자료구조를 구현해보자.

### container/list

    package main
    
    import (
        "container/list"
        "log"
    )
    
    func main() {
        lst := list.New()
        lst.PushBack(1)
        lst.PushBack(2)
        lst.PushBack(3)
    
        log.Println(lst.Len())
    }
    

위와 같이 `container/list` 패키지를 import하면, 손쉽게 linked list를 사용할 수 있다.

개발을 하면서 linked list를 사용해야 한다면, 꽤나 시간을 단축시킬 수 있을 것이다.

list를 순회하고 싶다면 아래와 같은 방법도 가능하다.

    package main
    
    import (
        "container/list"
        "fmt"
        "log"
    )
    
    func main() {
        lst := list.New()
        lst.PushBack(1)
        lst.PushBack(2)
        lst.PushBack(3)
    
        log.Println(lst.Len())
    
        for e := lst.Front(); e != nil; e = e.Next() { // 연결 리스트의 맨 앞부터 끝까지 순회
            fmt.Println(e.Value)
        }
    }
    

### container/heap

다음은 heap 패키지이다. 필자는 최근 회사에서 체결엔진/오더북을 구현하면서 min heap과 max heap을 구현할 일이 있었는데,

container/heap 패키지를 통해 간단하게 구현할 수 있었다.

heap 패키지에서는 기본적으로 다음과 같은 인터페이스가 필요하다.

    package heap 
    
    type Interface interface {
        Len() int
        Less(i, j int) bool
        Swap(i, j int)
        Push(x any)
        Pop() any  
    }
    

한 번 구현해서 사용해보자. 예제에서는 min heap을 구현해본다.

    package main
    
    import (
        "container/heap"
        "log"
    )
    
    type IMinHeap interface {
        heap.Interface
    }
    
    type MinHeap struct {
        heap []uint
    }
    
    func (m *MinHeap) Len() int {
        return len(m.heap)
    }
    
    func (m *MinHeap) Less(i, j int) bool {
        return m.heap[i] < m.heap[j]
    }
    
    func (m *MinHeap) Swap(i, j int) {
        m.heap[i], m.heap[j] = m.heap[j], m.heap[i]
    }
    
    func (m *MinHeap) Push(x any) {
        m.heap = append(m.heap, x.(uint))
    }
    
    func (m *MinHeap) Pop() any {
        old := m.heap
        n := len(old)
        element := old[n-1]
        m.heap = old[0 : n-1]
        return element
    }
    
    func main() {
        minHeap := &MinHeap{heap: []uint{}}
    
        heap.Init(minHeap)
    
        heap.Push(minHeap, uint(10))
        heap.Push(minHeap, uint(20))
        heap.Push(minHeap, uint(50))
        heap.Push(minHeap, uint(5))
    
        log.Println(heap.Pop(minHeap)) // 5
        log.Println(heap.Pop(minHeap)) // 10
        log.Println(heap.Pop(minHeap)) // 20
        log.Println(heap.Pop(minHeap)) // 50
    }
    

Less 조건의 부호만 반대로 바꿔줘도 max heap으로 바꾸어 사용할 수 있어 편하다.

### container/ring

다음은 ring이다. ring은 비교적 사용할 일이 많이 없는 듯 보이지만, 알아두면 때때로 도움이 될 수도 있다.

개인적으로는 list를 쓰는 편이긴 하다.

    package main
    
    import (
        "container/ring"
        "fmt"
    )
    
    func main() {
        data := []string{"Maria", "John", "Andrew", "James"}
        r := ring.New(len(data))       // 노드의 개수를 지정하여 링 생성
        for i := 0; i < r.Len(); i++ { // 링 노드 개수만큼 반복
            r.Value = data[i] // 링의 노드에 값 넣기
            r = r.Next()      // 다음 노드로  이동
        }
    
        r.Do(func(x interface{}) { // 링의 모든 노드 순회
            fmt.Println(x)
        })
    
        // "Maria" 
        // "John" 
        // "Andrew"
        // "James"
    }
    

두 개의 ring을 연결하는 것도 물론 가능하다.

    package main
    
    import (
        "container/ring"
        "fmt"
    )
    
    func main() {
        data := []string{"Maria", "John", "Andrew", "James"}
        r := ring.New(len(data))       // 노드의 개수를 지정하여 링 생성
        for i := 0; i < r.Len(); i++ { // 링 노드 개수만큼 반복
            r.Value = data[i] // 링의 노드에 값 넣기
            r = r.Next()      // 다음 노드로  이동
        }
    
        r.Do(func(x interface{}) { // 링의 모든 노드 순회
            fmt.Println(x)
        })
    
        // "Maria" 
        // "John" 
        // "Andrew"
        // "James"
    
        newData := []uint{1, 2, 3, 4}
    
        r2 := ring.New(len(newData))
        for i := 0; i < r2.Len(); i++ { // 링 노드 개수만큼 반복
            r2.Value = newData[i] // 링의 노드에 값 넣기
            r2 = r2.Next()        // 다음 노드로  이동
        }
    
        r3 := r.Link(r2)
    
        r3.Do(func(x interface{}) { // 링의 모든 노드 순회
            fmt.Println(x)
        })
        // John
        // Andrew
        // James
        // Maria
        // 1
        // 2
        // 3
        // 4
    }

---

*Originally published on [Primrose](https://paragraph.com/@primrose/golang-container-package)*
