我会迭代切片索引的向量。


单索引迭代器:


// Iterator of a slice index. `len` equals to the length of the slice

type IdxIter struct {

    idx uint

    len uint

}


// Returns true is the iteration is over.

func (i IdxIter) Done() bool {

    return i.idx >= i.len

}


// Builds the next iteration value. If called for the last index,

// the next value's `Done` returns `true`.

func (i *IdxIter) Next() {

    i.idx++

}


// Resets the iterator

func (i *IdxIter) Reset() {

    i.idx = 0

}


// The index value

func (i IdxIter) Idx() uint {

    return i.idx

}

索引向量的迭代器:


// Index iterator for a slice of slices

type IdxVectorIter []IdxIter


// Returns true is the iteration is over.

func (ii IdxVectorIter) Done() bool {

    last := len(ii) - 1

    return ii[last].Done()

}


// Builds the next iteration value. If called for the last index vector,

// the next value's `Done` returns `true`.

func (ii IdxVectorIter) Next() {

    if len(ii) == 0 {

        return

    }

    last := len(ii) - 1

    for pos := range ii[:last] {

        ii[pos].Next()

        if ii[pos].Done() {

            ii[pos].Reset()

        } else {

            return

        }

    }

    ii[last].Next()

}

这样,切片切片的迭代就很简单了:


func main() {

    words := [][]string{

        {"lorem", "ipsum"},

        {},

        {"Alpha", "Beta", "Gamma"},

        {"X", "Y", "Z"},

    }

    // Fixed buffer for the combinations of words

    dst := make([]string, len(words))

    // Iteration loop

    for ii := NewIdxVectorFromSlices(words); !ii.Done(); ii.Next() {

        GetTo(words, dst, ii)

        fmt.Printf("%v\n", dst)

    }

}

完整代码https://go.dev/play/p/ecjjcAEexZO


输出


[lorem  Alpha X]

[ipsum  Alpha X]

[lorem  Beta X]

[ipsum  Beta X]

[lorem  Gamma X]

[ipsum  Gamma X]

[lorem  Alpha Y]

[ipsum  Alpha Y]

[lorem  Beta Y]

[ipsum  Beta Y]

[lorem  Gamma Y]

[ipsum  Gamma Y]

[lorem  Alpha Z]

[ipsum  Alpha Z]

[lorem  Beta Z]

[ipsum  Beta Z]

[lorem  Gamma Z]

[ipsum  Gamma Z]