迭代器是什么

迭代器(iterator)有时又称光标(cursor)

  • 迭代器是程序设计的软件设计模式

  • 迭代器模式提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的标识。

在表现效果上看,是可以在容器对象(例如链表或数组)上遍历访问的接口。

设计人员无需关心容器对象的内存分配的实现细节

可以用foreach遍历的类,都是实现了迭代器的类

标准迭代器的实现方法

using System.Collections;
using UnityEngine;

public class Testing : MonoBehaviour
{
    private void Start()
    {
        MyCustomList list = new MyCustomList();
        for(int i = 0; i < 10; i++)
        {
            list.Add(i);
        }

        //foreach本质 
        //1.先获取in后面这个对象的 IEnumerator
        //  会调用对象其中的GetEnumerator方法 来获取
        //2.执行得到这个IEnumerator对象中的 MoveNext方法
        //3.只要MoveNext方法的返回值时true 就会去得到Current
        //  然后复制给 item
        foreach (int item in list) { 
            print(item);
        }

        foreach (int item in list)
        {
            print(item);
        }
    }
}

public class MyCustomList : IEnumerable, IEnumerator
{
    private int[] ints = new int[10];
    public int Count;
    public int Capital;

    //从-1开始的光标 用于表示 数据得到了哪个位置
    private int cursor = -1;

    public object Current {
        get
        {
            return ints[cursor];
        }
    }

    public MyCustomList(int Capital = 10)
    {
        ints = new int[Capital];
        this.Capital = Capital;
        this.Count = 0;
    }

    public void Add(int value)
    {
        if(Count >= Capital)
        {
            // 扩容逻辑
            throw new System.Exception("需要填写扩容逻辑");
        }
        ints[Count++] = value;
    }


    public IEnumerator GetEnumerator()
    {
        Reset();
        return this;
    }

    public bool MoveNext()
    {
        cursor++; //移动光标
        return Count > cursor;  //是否溢出 溢出就不合法
    }

    //reset是重置光标位置 一般写在获取 IEnumerator对象这个函数中
    //用于第一次重置光标位置
    public void Reset()
    {
        cursor = -1;
    }
}

yield return 本质

当一个方法包含 yield return 语句时,编译器会自动生成一个实现了 IEnumerator 接口的类(对于 IEnumerable<T>,则是实现了 IEnumerator<T>)。这个生成的类负责维护状态,并且会在每次调用 MoveNext() 方法时执行到下一个 yield return 语句的位置。也就是说,yield return 并不是立即执行并返回所有结果,而是使得方法在每次请求下一个元素时才计算并返回该元素。

yield return 语法糖实现迭代器

自定义类不需要去实现接口,但要让这个类变成迭代器,这个类必须有GetEnumerator方法。

public class MyCustomList
{
    private int[] ints = new int[10];
    public int Count;
    public int Capital;

    public MyCustomList(int Capital = 10)
    {
        ints = new int[Capital];
        this.Capital = Capital;
        this.Count = 0;
    }

    public void Add(int value)
    {
        if(Count >= Capital)
        {
            // 扩容逻辑
            throw new System.Exception("需要填写扩容逻辑");
        }
        ints[Count++] = value;
    }


    public IEnumerator GetEnumerator()
    {
        for(int i = 0; i < Count; i++)
        {
            yield return ints[i];
        }
    }
}

yield return 语法糖的泛型实现迭代器

public class MyCustomList<T>
{
    private T[] ints = new T[10];
    public int Count;
    public int Capital;

    public MyCustomList(int Capital = 10)
    {
        ints = new T[Capital];
        this.Capital = Capital;
        this.Count = 0;
    }

    public void Add(T value)
    {
        if(Count >= Capital)
        {
            // 扩容逻辑
            throw new System.Exception("需要填写扩容逻辑");
        }
        ints[Count++] = value;
    }


    public IEnumerator GetEnumerator()
    {
        for(int i = 0; i < Count; i++)
        {
            yield return ints[i];
        }
    }
}