迭代器与协程

通过foreach,我们可以遍历List元素。
其中的原理便是使用了迭代器,迭代器里用current定义到当前元素,MoveNext()转移到下一元素并返回bool值

        List<int> ages=new List<int>();
        for (int i = 0; i < 5; i++)
        {
            ages.Add(i);
        }
        IEnumerator ie = ages.GetEnumerator();
        while (ie.MoveNext())
        {
            print(ie.Current);
        }

迭代器的接口是IEnumerator,IEnumerator接口的定义如下:

using System.Runtime.InteropServices;
namespace System.Collections
{
    [ComVisible(true)]
    [Guid("496B0ABF-CDEE-11D3-88E8-00902754C43A")]
    public interface IEnumerator
    {
        object Current { get; }
        bool MoveNext();
        void Reset();
    }
}
成员说明:
Current 遍历当前类型时,存储当前元素。
MoveNext()  每调用一次,移动到下一个元素,返回下一个元素是否为空
Reset()   重置到列表最开始
枚举器就是实现IEnumerator接口,通过MoveNext()获取下一个元素来遍历每个元素的方法。

下方为List里面的枚举器Enumerator代码

        public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable
        {
            public T Current { get; }

            public void Dispose();
            public bool MoveNext();
        }

我们也可以自己定义返回的IEnumerator

public  IEnumerator  GetEnumerator()
    {
        print(1);
        yield return 1;
        print(2);
        yield return 2;
        print(3);
        yield return "枚举器";
    }

包含yield语句的方法或属性称为迭代块

而yield return则是实现了IEnumerator接口和IDisposable接口的属性和方法,相当于迭代器的实例。
当以后每次迭代器实例调用MoveNext()时,将逐一实现迭代块里的行为。比如上方就有3个迭代块。

每次MoveNext()方法后,改变当前迭代位置为下一个元素位置。

public class update2Coroutine : MonoBehaviour {
    Update2CoroutineTest update2CoroutineTest = new Update2CoroutineTest();
    IEnumerator e;
    public update2Coroutine()
    {
         e = update2CoroutineTest.GetEnumerator();
    }
    // Use this for initialization
    void Start () {
    }
    // Update is called once per frame
    void Update () {
        if (e.MoveNext())
        {
        }
    }
}
public class Update2CoroutineTest
{
    public IEnumerator GetEnumerator()
    {
        Debug.Log("协程:"+1);
        yield return 0;
        Debug.Log("协程:" + 2);
        yield return 0;
        Debug.Log("协程:" + "枚举器");
        yield return 0;
    }
}

每隔一段时间输出为:
协程:1
协程:2
协程:枚举器
    void Start()
    {
        StartCoroutine(TestIt());
    }
    IEnumerator TestIt()
    {
        print("开始走路");
        yield return 0;
        print("走进商店");
        yield return 0;
        print("开始购物");
        yield return 0;
        //yield return null;
    }

从而实现了某段代码的等待,一步步来,而不是全部输出。

从上面可以看出 ,在update()方法模拟协程和使用unity自带StartCoroutine()方法启动协程效果差不多。
但是唯一确定的一点就是unity也是通过枚举一步步运行程序块的。类似update()模拟的协程,每次遇到yield return ,就执行yield 类型的
MoveNext()方法,改变当前迭代位置为下一个元素位置。等待下一次MoveNext()方法调用。StartCoroutine()方法会不停的调用MoveNext()方法方法(这样就类似于foreach)。直到枚举结束。

比如下面这段代码,便相当于自己写了一个Update语句

    IEnumerator MyEnumerator()
    {
        while (true)
        {
            MyUpdate();
            yield return 0;
        }
    }

    void MyUpdate()
    {
        i++;
        print(i);
    }
    
    // Update is called once per frame
    void Update()
    {
        //    i++;
        //    print("Update:"+i);
    }

值得注意的是,yield return 后面跟的值除了unity自带的类(如:new WaitForSeconds(0.2f)、YieldInstruction和协程语句块(返回值为 IEnumerator的方法 ) ,其他值没有意义(yield return 0和yield return null其实都是一样的,只是遇到yield return就做相同处理,不会去处理后面跟的值了)。

yield return new WaitForSeconds(1f);就能让协程每隔一秒再执行。

对比协程和Update的等待时间:

你会发现不管你设置的协程时间间隔多小(前提小于update的时间间隔),打印的时间和update的时间非常接近,
这说明你的协程时间间隔最小就是update的时间间隔。不可能再短了。即使你设置的比update时间间隔小。协程也只会执行update 的时间间隔了。
正好也验证了上面所说的:
在update()方法模拟协程和使用unity自带StartCoroutine()方法启动协程效果差不多。看来unity实现的StartCoroutine()启动协程和我们 update()模拟是一样的。但是也不确定到底是不是通过类似update()方法实现的。

unity协程详细说明—创世界—

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值