吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2701|回复: 1
收起左侧

[Python 原创] [Lua&C」lua闭包(迭代器)简单应用|仿一个python中的range函数

  [复制链接]
lovingxiaobing 发表于 2018-9-8 20:25
小冰在网上搜了一下Lua c api,貌似对于用c实现lua闭包的的文章几乎没有<没有科学依据的说>。
萌新小冰就来教一下大家如何用C写一个lua的闭包函数吧~

等会会用用到的LUA API:
  • lua_gettop
  • luaL_checkinteger
  • lua_tointeger
  • lua_setupvalue
  • lua_upvalueindex
  • lua_pushinteger
  • lua_pushcclosure
  • luaL_newlib


嘻嘻,相信大家的自学能力还是蛮ok哒
栈的元素特点就是先进后出嘛,栈顶是-1,栈低是1

大家也看过科幻片吧,这个平常用到栈就比作时现实空间<科幻>,等会会用到异元次空间<科幻>:伪索引。就像现实和虚拟,不能不承认,他们都是存在。

光说不行呀<实践是理论的唯一标准>

先来一段lua闭包


local range

range = function (n)
    local start = 0
    local target = n
    local step = 1
    local now = start

    local function range_element()
        if now >= target then
            return nil
        end

        now = now + step
        return now  --闭包的返回值
    end

    return range_element    --把闭包函数返回给 for
end

print("value:")

for i in range(10) do
    print(i)
end


结果:
[Shell] 纯文本查看 复制代码
value:
1
2
3
4
5
6
7
8
9
10


上面的range函数中的局部变量叫做range_element的上值,emmm,这是chinglish吧,英文名叫做:upvalue
上值的作用就是给闭包函数用的,作为闭包函数每次的返回值,作为迭代器结束循环的条件,作为,,,,好像没啦~


前面扯淡了那么多,主题来了!!!

问题来了,在C中咋整????

其实原理跟lua代码差不多,上代码吧

//file: myiter.c

#define LUA_LIB
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static int range_element(lua_State *L)
{
    lua_Integer now, start, target, step;

    //把值从异次元空间取出来
    start = lua_tointeger(L, lua_upvalueindex(1));
    target = lua_tointeger(L, lua_upvalueindex(2));
    step = lua_tointeger(L, lua_upvalueindex(3));
    now = lua_tointeger(L, lua_upvalueindex(4));

    if (now >= target) return 0;    //返回nil结束lua中的for

    lua_pushinteger(L, now);    //要返回的值
    now += step;
    lua_pushinteger(L, now);    //记录本次的值
    lua_replace(L, lua_upvalueindex(4));    //替换旧值

    return 1;
}

static int l_range(lua_State *L)
{
    lua_Integer now, start = 0, target, step = 1;
    now = start;

    luaL_checkinteger(L, 1);

    lua_pushcclosure(L, range_element, 4);

    //把上值传入异元次空间
    //最小值
    lua_pushinteger(L, start);
    lua_setupvalue(L, -2, 1);   //闭包函数位于栈的-2位置,而这个1上值的伪索引

    //再来几个上值
    lua_pushinteger(L, target);
    lua_setupvalue(L, -2, 2);
    //------------------
    lua_pushinteger(L, step);
    lua_setupvalue(L, -2, 3);

    //这个记录当前量
    lua_pushinteger(L, now);
    lua_setupvalue(L, -2, 4);

    return 1;
}

static const struct luaL_Reg myiter[] =\
{
    {"range", l_range},
    {NULL, NULL}
};

LUALIB_API int luaopen_myiter(lua_State *L)
{
    luaL_newlib(L, myiter);
    return 1;
}

--file: myiter.lua
myiter = require "myiter"

local range = myiter.range

print("value:")
for i in range(10) do
    print(i)
end


ok!编译并执行!

[Shell] 纯文本查看 复制代码
gcc myiter.c -o myiter.so -shared -fPIC -llua

[Shell] 纯文本查看 复制代码
lua myiter,lua
value:
0
1
2
3
4
5
6
7
8
9


哈哈哈看来已经接近range函数啦。

再来完善一下吧~~

直接上代码:

/*
* author: 小冰哟
*/

/*
* range([start,] target[, step])<不支持浮点数>类似于python中的range(...)
*/

#define LUA_LIB
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static int l_closurefunc(lua_State *L)
{
    lua_Integer now, start, target, step;

    start = lua_tointeger(L, lua_upvalueindex(1));
    target = lua_tointeger(L, lua_upvalueindex(2));
    step = lua_tointeger(L, lua_upvalueindex(3));
    now = lua_tointeger(L, lua_upvalueindex(4));

    if (((now >= target) && (step > 0)) \
        || ((now <= target) && (step < 0)))
            return 0;

    lua_pushinteger(L, (now != start) ? now : start);

    now += step;
    lua_pushinteger(L, now);
    lua_replace(L, lua_upvalueindex(4));    //当前变量

    return 1;
}

static int l_range(lua_State *L)
{
    lua_Integer n[3] = {0, 0, 1}; //[0]:start|[1]:target|[2]:step
    unsigned char i;

    switch (lua_gettop(L)) {
        case 1:
            n[1] = luaL_checkinteger(L, 1);

            if (n[1] == 0) return 0;
            n[2] = (n[1] > 0) ? n[2] : -n[2];
            break;
        case 2:
            n[0] = luaL_checkinteger(L, 1);
            n[1] = luaL_checkinteger(L, 2);
            break;
        case 3:
            n[0] = luaL_checkinteger(L, 1);
            n[1] = luaL_checkinteger(L, 2);
            n[2] = luaL_checkinteger(L, 3);
            break;
        default:
            return 0;
    }

    lua_pushcclosure(L, l_closurefunc, 4);

    for (i = 0; i < 3; i++) {
        lua_pushinteger(L, n[i]);
        lua_setupvalue(L, -2, (i + 1));
    }

    //当前变量
    lua_pushinteger(L, n[0]);
    lua_setupvalue(L, -2, 4);

    return 1;
}

static const struct luaL_Reg l_miter[] =\
{
    {"range", l_range},
    {NULL, NULL}
};

LUALIB_API int luaopen_miter(lua_State *L)
{
    luaL_newlib(L, l_miter);

    lua_pushstring(L, "author");
    lua_pushstring(L, "小冰哟|lovingxiaobing");
    lua_rawset(L, 3);

    return 1;
}


好啦,小冰就跟大家唠嗑到这啦~

给大家一个查询lua c api 的网,中文的哟。
https://www.runoob.com/manual/lua53doc/contents.html

喜欢小冰的文章,支持一下哟,mua~

小甲鱼:programming change the world!

免费评分

参与人数 1吾爱币 +5 热心值 +1 收起 理由
苏紫方璇 + 5 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Right_Hai 发表于 2018-9-8 22:22
学习学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 20:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表