Dart Generic Stack
A stack is a last-in, first-out collection. A generic stack holds one element type chosen by the caller.
Push and pop with strings
Three names go onto the stack. They come back off in reverse order.
class Stack<T> {
final List<T> _items = [];
void push(T item) {
_items.add(item);
}
T? pop() {
if (_items.isEmpty) {
return null;
}
return _items.removeLast();
}
T? peek() {
if (_items.isEmpty) {
return null;
}
return _items[_items.length - 1];
}
bool get isEmpty {
return _items.isEmpty;
}
}
void main() {
var stack = Stack<String>();
stack.push('alpha');
stack.push('beta');
stack.push('gamma');
print('top: ${stack.peek()}');
print(stack.pop());
print(stack.pop());
print(stack.pop());
}An int stack
The same class now holds ints. No new class was written for the new element type.
class Stack<T> {
final List<T> _items = [];
void push(T item) {
_items.add(item);
}
T? pop() {
if (_items.isEmpty) {
return null;
}
return _items.removeLast();
}
T? peek() {
if (_items.isEmpty) {
return null;
}
return _items[_items.length - 1];
}
bool get isEmpty {
return _items.isEmpty;
}
}
void main() {
var stack = Stack<int>();
stack.push(1);
stack.push(2);
stack.push(3);
print(stack.pop());
print(stack.pop());
print(stack.pop());
}Peek and isEmpty
An empty stack peeks as null. After one push, peek shows the value and isEmpty turns false.
class Stack<T> {
final List<T> _items = [];
void push(T item) {
_items.add(item);
}
T? pop() {
if (_items.isEmpty) {
return null;
}
return _items.removeLast();
}
T? peek() {
if (_items.isEmpty) {
return null;
}
return _items[_items.length - 1];
}
bool get isEmpty {
return _items.isEmpty;
}
}
void main() {
var stack = Stack<String>();
print('isEmpty: ${stack.isEmpty}');
print('peek: ${stack.peek()}');
stack.push('x');
print('peek: ${stack.peek()}');
print('isEmpty: ${stack.isEmpty}');
}Example
class Stack<T> {
final List<T> _items = [];
void push(T item) {
_items.add(item);
}
T? pop() {
if (_items.isEmpty) {
return null;
}
return _items.removeLast();
}
T? peek() {
if (_items.isEmpty) {
return null;
}
return _items[_items.length - 1];
}
bool get isEmpty {
return _items.isEmpty;
}
int get length {
return _items.length;
}
}
void main() {
var tasks = Stack<String>();
tasks.push('email');
tasks.push('report');
print('next: ${tasks.pop()}');
print('next: ${tasks.pop()}');
print('left: ${tasks.length}');
}Key points
- push adds a value to the top of the stack.
- pop removes the top value and returns it.
- peek reads the top value without removing it.
- pop and peek return T? here, so an empty stack gives null instead of an error.
- The backing list stays private, so outside code cannot disturb the order.
In this example, two task names go onto the stack. pop takes report first because it went on last. email follows, and the length reads 0 once both are gone.
Note
the same Stack class serves strings, numbers, and any other single type.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท DartPad
Exercise
What does pop return on an empty stack in this lesson?