Search code examples
gogenericsstackabstract-data-type

Initializing generic slice with size inside a struct


I'm trying to build a LIFO stack. I've created a Stack[T any] interface and a dynamicStack[T any] struct. dynamicStack has a data []T field and an index int field. When a dynamicStack is created, I want data to be initialized empty, of fixed size 1 and type T. Statement comes up: "cannot use [0]T{} (value of type [0]T) as []T value in assignment" when I try to do so.

type Stack[T any] interface {
    IsEmpty() bool
    SeeTop() T
    AddToStack(T)
    Unstack() T
}
type dynamicStack[T any] struct {
    data    []T
    index int
}
func CreateDynamicStack[T any]() Stack[T] {
    s := new(dynamicStack[T])
    s.data = [0]T{} // Problem
    s.index = 0
    return s
}

I've tried using const instead of "0", different sizes and even initializing the array as non-empty but nothing works.

I'm not trying to use append() method and I need a fixed size array as my plan is to resize the array whenever it's full or whenever it's half empty.

Any ideas?


Solution

  • s.data is a slice, you should initialize it as a slice :

    s.data = make([]T, 0)
    

    Actually, go handles a nil slice pretty much like an empty slice, so you don't even need to initialize s.data in your structure. See the example below for an illustration.


    In go, there is a difference between a slice type []T and an array type [n]T.

    For a detailed explanation of how slices and arrays behave, see this article by Andrew Gerrand:
    Go Slices: usage and internals


    // example of slice usage:
    func testSlice() {
        var s []int
    
        fmt.Println("length:", len(s))
        for i, x := range s {
            fmt.Println("iterating:", i, x) // never executed, the slice is empty
        }
    
        newSlice := append(s, 1)  // a slice allocation happens here
        fmt.Println("result of append(s,1):", newSlice)
    
        emptySlice := make([]int, 0)
    
        // the only visible different thing is comparing to nil:
        if s == nil {
            fmt.Println("s is nil")
        }
        if emptySlice == nil {
            fmt.Println("emptySlice is nil") // not printed
        }
    
        // if you stick to checking the *length* of your slice, you will
        // have a consistent behavior:
        if len(s) == 0 {
            fmt.Println("s is empty")
        }
        if len(emptySlice) == 0 {
            fmt.Println("emptySlice is empty")
        }
    }
    

    playground: https://go.dev/play/p/kB1g2Iq-n6u