The Iterator Design Pattern is collection dependent. For example, if you are given a List:
List={1,2,3,4,5,6}
you may traverse in this way:
list := []int{1, 2, 3, 4, 5, 6}
for _, v := range list {
println(v)
}
We don't need to know whether the underlying layer of the list is an Array or a Linked List.
But if I give a Set
Set={4,3,2,1,5,6}
- how do you traverse it?
- Do you need to know the underlying data structure to traverse?
- Is there a way to handle all collections with a unified type of interface?
At this time, the Iterator Design Pattern is used
iterator.go
package designpattern
type Iterator[V any] interface {
HasNext() bool
Next() V
}
type ArrayList[V any] struct {
data []V
}
func NewArrayList[V any](v ...V) ArrayList[V] {
return ArrayList[V]{data: v}
}
func (array *ArrayList[V]) Iterator() *ArrayListIterator[V] {
return &ArrayListIterator[V]{currIndex: 0, list: array}
}
type ArrayListIterator[V any] struct {
currIndex int
list *ArrayList[V]
}
func (iterator *ArrayListIterator[V]) HasNext() bool {
return len(iterator.list.data) > iterator.currIndex
}
func (iterator *ArrayListIterator[V]) Next() V {
if len(iterator.list.data) > iterator.currIndex {
v := iterator.list.data[iterator.currIndex]
iterator.currIndex++
return v
} else {
var v V
return v
}
}
type HashSet[V comparable] struct {
data map[V]bool
}
func NewHashSet[V comparable](v ...V) HashSet[V] {
mapPool := make(map[V]bool)
for _, element := range v {
if _, ok := mapPool[element]; !ok {
mapPool[element] = true
}
}
return HashSet[V]{data: mapPool}
}
func (hashSet *HashSet[V]) Iterator() *HashSetIterator[V] {
keys := make([]V, 0, len(hashSet.data))
for k := range hashSet.data {
keys = append(keys, k)
}
return &HashSetIterator[V]{currIndex: 0, set: keys}
}
type HashSetIterator[V any] struct {
currIndex int
set []V
}
func (iterator *HashSetIterator[V]) HasNext() bool {
return len(iterator.set) > iterator.currIndex
}
func (iterator *HashSetIterator[V]) Next() V {
if len(iterator.set) > iterator.currIndex {
v := iterator.set[iterator.currIndex]
iterator.currIndex++
return v
} else {
var v V
return v
}
}
iterator_test.go
package designpattern_test
import (
designpattern "ptarmigan-golang-design-pattern/src"
"testing"
)
func TestArrayIterator(t *testing.T) {
array := designpattern.NewArrayList(1, 2, 3, 4, 5, 6)
iterator := array.Iterator()
var iteratorCount = 6
index := 0
for iterator.HasNext() {
println(iterator.Next())
index++
}
if index != iteratorCount {
t.Error("Iterator needs 6 iterations")
}
if iterator.HasNext() || 0 != iterator.Next() {
t.Error("Iterator has not finished iteration")
}
}
func TestHashSetIterator(t *testing.T) {
hashSet := designpattern.NewHashSet(1, 2, 3, 4, 5, 6)
iterator := hashSet.Iterator()
var iteratorCount = 6
index := 0
for iterator.HasNext() {
println(iterator.Next())
index++
}
if index != iteratorCount {
t.Error("Iterator needs 6 iterations")
}
if iterator.HasNext() || 0 != iterator.Next() {
t.Error("Iterator has not finished iteration")
}
}
func TestArray(t *testing.T) {
list := []int{1, 2, 3, 4, 5, 6}
for _, v := range list {
println(v)
}
}