Generic Data Structure: Stack
Generic programming allows us to write code that can operate on different data types without being rewritten for each type. Go 1.18 introduced generics, enabling this powerful feature. This challenge asks you to implement a generic stack data structure in Go, demonstrating your understanding of type parameters and constraints.
Problem Description
You are tasked with creating a generic Stack data structure in Go. The stack should support the following operations:
- Push(value interface{}): Adds a new element to the top of the stack.
- Pop(): Removes and returns the element at the top of the stack. Returns
nilif the stack is empty. - Peek(): Returns the element at the top of the stack without removing it. Returns
nilif the stack is empty. - IsEmpty(): Returns
trueif the stack is empty,falseotherwise. - Size(): Returns the number of elements in the stack.
The stack should be generic, meaning it can hold elements of any type. You'll need to define a Stack type that uses type parameters to achieve this. Consider how to handle potential type assertions when popping or peeking.
Examples
Example 1:
Input:
stack := NewStack[int]()
stack.Push(1)
stack.Push(2)
stack.Push(3)
Output:
3
Explanation:
Peek() returns the top element (3) without removing it.
Example 2:
Input:
stack := NewStack[string]()
stack.Push("hello")
stack.Push("world")
Output:
"world"
Explanation:
Pop() removes and returns the top element ("world").
Example 3:
Input:
stack := NewStack[float64]()
stack.Push(3.14)
stack.Push(2.71)
stack.Pop()
stack.Pop()
Output:
nil
Explanation:
After popping both elements, the stack is empty, so Pop() returns nil.
Constraints
- The stack should be implemented using a slice.
- The
Pushoperation should have a time complexity of O(1). - The
Pop,Peek,IsEmpty, andSizeoperations should have a time complexity of O(1). - The stack should handle empty stack conditions gracefully by returning
nilforPopandPeek. - The type parameter
Tshould be constrained to be comparable. This is not strictly required for the basic functionality, but it's a good practice for potential future extensions (e.g., sorting the stack).
Notes
- You'll need to define a
NewStackfunction that creates a newStackinstance with a specified type parameter. - Consider using interfaces to allow the stack to hold any type. However, be mindful of type assertions when retrieving values.
- Think about how to handle potential panics if you attempt to pop or peek from an empty stack. Returning
nilis the preferred approach. - While not explicitly required, consider adding a
Clear()method to remove all elements from the stack. This can be a useful addition to the data structure. - The
interface{}type allows for any type to be stored, but you'll need to use type assertions when retrieving values to use them with their original type. This is a key aspect of working with generics in Go.