Lua:面向对象/C之间的交互

这篇具有很好参考价值的文章主要介绍了Lua:面向对象/C之间的交互。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前段时间对平台的任务感兴趣,其要求是一周内12篇博文,尝试了之后发现还是太敷衍了,之后还是回归到内容本身上来,尽量保证一篇博文的内容能涵盖足够多的知识点或者足够深的思考成分。

面向对象

面向对象主要有三个方面:封装、继承和多态。Lua若做到了这三点,则认为是也具有面向对象的特征。Lua可以通过表来实现上面三个特征。

类本身的概念就是创建对象的模板。然而Lua本身不存在类的概念,但是可以创建一个原型(prototype)对象,当调用不属于对象的某些操作时,会最先到prototype中查找这些操作。在lua中若想要对象b作为对象a的prototype只需要以下代码:

setmetatable(a, {__index = b}) 

继承

有了index后,在a域找不到的相关属性就会选择在b域查找。如若有更多的对象选择继承b,则覆写以上代码即可,此时的b就被用来当作是prototype了。比如如下实例代码,可选择将Account作为prototype对象:

Account = {}
Account.balance = 0
function Account.new (o)
    o = o or {} -- create object if user does not provide one 
    setmetatable(o, Account)
    Account.__index = Account
   return o
end

function Account:deposit (v)
    self.balance = self.balance + v
end

a = Account.new{balance = 100}
a:deposit(100)
print(a.balance) --200

lua面向对象有一个有趣的方式就是不需要创建新类去指定新的对象行为,可以直接在对象中实现相关操作即可,比如上面的a对象,可以直接赋予其新的函数:

function a:NewBalance()
    self.balance = 0
end
print(a.balance) -- 200
a:NewBalance()
print(a.balance) -- 0

也可以用相同方式实现多重继承,即实现index metamethod,使其在多个父类中查找子类不存在的域:

function search (k, plist) 
    for i=1, #plist do
        local v = plist[i][k] -- try 'i'-th superclass 
        if v then return v end
    end
end

function createClass(...)
    local arg = {...}
    local c = {}
    setmetatable(c, {__index = function (t, k)
        return search(k, arg)
    end})
end

privacy封装

lua本身不具有私有性访问机制。lua设计初衷是小型到中型的程序设计,避免太冗余和太多的人为限制。但是我们依然可以有方案实现私有封装操作:创建一个函数工厂,内设状态和闭包,外部只能获取到return的函数table而没有状态:

function newAccount (initialBalance) 
    local self = {balance = initialBalance} 
    local withdraw = function (v) 
     self.balance = self.balance - v 
    end 
    local deposit = function (v) 
     self.balance = self.balance + v 
    end 
    local getBalance = function () return self.balance end
    return { 
        withdraw = withdraw, 
        deposit = deposit, 
        getBalance = getBalance 
    } 
end

如上所示,除了函数newAccount内部可控制balance变量以外,都无法再对balance进行操作,外部只能调用函数接口。

C API

C API是一个C代码与Lua进行交互的函数集,分为以下几个部分:读写Lua全局变量的函数,调用Lua函数的函数,运行Lua代码片段的函数,注册C函数然后可在Lua中被调用的函数等。

在 C 和 Lua 之间通信关键内容在于一个虚拟的栈。几乎所有的 API 调用都是对栈上的值进行操作,所有 C 与 Lua 之间的数据交换也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。栈的使用解决了 C 和 Lua 之间两个不协调的问题:第一,Lua 会自动进行垃圾收集,而 C 要求显式的分配存储单元,两者引起的矛盾。第二,Lua 中的动态类型和 C 中的静态类型不一致引起的混乱。

堆栈

Lua和C之间交互主要面临两个问题,一个是内存管理,一个是静态类型和动态类型的不一致性。比如a[k] = v这一段代码,k和v很可能是好几种不同的类型,而且由于metatable的存在,a也可能会有不同的类型。如果不同类型之间的赋值函数组合在一起,很有可能需要几十个不同的函数来完成这一个操作。

当然我们可以在C侧声明union类型解决该问题,倘若我们采用settable函数来实现a[k] = v这段代码:

void lua_settable (lua_Value a, lua_Value k, lua_Value v);

但是这会面临另一个问题:内存管理。如果把lua值保存在C侧,lua引擎便不清楚这个值是否还在使用,很可能会误认为某个值是垃圾从而收集它。并且,lua的这个动态类型是非常复杂的,映射到其他语言会非常困难,lua设计初衷并非只是C/C++,还要和其他主流语言比如Java进行交互,不可能每一个语言都要完成类似这种的转换。

于是Lua API实现了一个抽象的栈在Lua和C之间交换值。无论你何时想要从 Lua 请求一个值(比如一个全局变量的值),调用 Lua,被请求的值将会被压入栈。无论你何时想要传递一个值给 Lua,首先将这个值压入栈,然后调用 Lua(这个值将被弹出)。虽然我们需要函数将C类型压入栈和函数从栈上取值,但是我们至少是避免了组合爆炸。而且这个栈由lua管理,垃圾回收器知道哪个值在被C使用。

Lua侧严格采用先进后出的方式操作栈,它只会改变栈顶部分;C侧却可以查询、删除、插入栈上的任何元素。

压入元素

可以将每种可用C来描述的Lua类型压栈:

void lua_pushnil (lua_State *L); 
void lua_pushboolean (lua_State *L, int bool); 
void lua_pushnumber (lua_State *L, double n); 
void lua_pushlstring (lua_State *L, const char *s, size_t length); 
void lua_pushstring (lua_State *L, const char *s); 

任意的字符串(char*类型,允许包含'\0'字符)用 lua_pushlstring,它要求一个明确的长度作为参数。以'\0'结束的字符串(const char*)用 lua_pushstring。

无论何时压入一个元素到栈上,都需要确保在栈上有空间来做这件事情。可以调用下面函数来检测栈上是否有足够需要的空间。

int lua_checkstack (lua_State *L, int sz);

查询元素

API用索引访问栈内元素。第一个入栈的索引是1,栈顶是-1,-2指的是栈顶下方的那个元素。通过lua_isnumber/lua_isstring等等函数来判断栈内某个元素是否是指定类型:

int lua_is... (lua_State *L, int index);

lua_isnumber 和 lua_isstring 函数不检查这个值是否是指定的类型,而是看它是否能被转换成指定的那种类型。例如,任何数字类型都满足 lua_isstring。

另外,通过lua_tonumber/lua_tostring等函数实现对类型的转换:

int lua_toboolean (lua_State *L, int index); 
double lua_tonumber (lua_State *L, int index); 
const char * lua_tostring (lua_State *L, int index); 
size_t lua_strlen (lua_State *L, int index); 

注意const修饰符,包括上方lua_pushstring函数,都意味着lua不允许将指向字符串的指针保存到访问他们的外部函数中。

其他堆栈操作

通过以下函数完成普通的堆栈操作:

int lua_gettop (lua_State *L); 
void lua_settop (lua_State *L, int index); 
void lua_pushvalue (lua_State *L, int index); 
void lua_remove (lua_State *L, int index); 
void lua_insert (lua_State *L, int index); 
void lua_replace (lua_State *L, int index);

顾名思义,gettop获取堆栈元素个数,settop设置栈大小,pushvalue复制索引index位置上的元素到栈顶,remove移除指定index位置上的元素,insert将栈顶元素插入到index位置上,replace将栈顶元素弹出并设置到指定index位置上。文章来源地址https://www.toymoban.com/news/detail-830042.html

到了这里,关于Lua:面向对象/C之间的交互的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • lua的用户数据的使用与c语言交互

    在 Lua 中,用户数据(userdata)是一种特殊的数据类型,它可以用来表示外部的 C 或 C++ 对象,并将它们传递给 Lua 程序使用。用户数据是 Lua 与其他语言或系统进行交互的主要方式之一,它可以让 Lua 程序与其他语言或系统进行无缝的集成。 用户数据的使用一般分为以下几个步

    2024年02月09日
    浏览(31)
  • # Lua与C++交互(二)———— 交互

    基础调用 再来温习一下 myName = “beauty girl” C++想要获取myName的值,根据规则,它需要把myName压入栈中,这样lua就能看到; lua从堆栈中获取myName的值,此时栈顶为空; lua拿着myName去全局表中查找与之对应的字符串; 全局表找到,并返回\\\"beauty girl\\\"; lua把\\\"beauty girl\\\"压入栈中;

    2024年02月11日
    浏览(34)
  • Lua与C++交互

    1、lua和c++交互机制是基于一个虚拟栈,C++和lua之间的所有数据交互都通过这个虚拟栈来完成,无论何时C++想从lua中调用一个值,被请求的值将会被压入栈,C++想要传递一个值给Lua,首选将整个值压栈,然后就可以在Lua中调用。 2、lua中提供正向和反向索引,区别在于证书永远

    2024年02月08日
    浏览(38)
  • lua与c#交互篇

    C# Call Lua :由C#文件先调用Lua解析器底层dll库(由C语言编写),再由dll文件执行相应的Lua文件; Lua Call C# : Wrap方式:首先生成C#源文件所对应的Wrap文件,由Lua文件调用Wrap文件,再由Wrap文件调用C#文件; C# Call Lua:C#把请求或数据放在栈顶,然后lua从栈顶取出该数据,在lua中做出

    2024年02月16日
    浏览(34)
  • Lua与Java的交互方案

    Lua 和 Java 之间的交互可以通过多种方式实现,每种方式都有其优点和适用场景。以下是几种常见的方案: 1. JNI(Java Native Interface) JNI 是 Java 提供的一种标准编程接口,它允许 Java 代码与本地应用程序或库(例如 C/C++ 编写的程序)进行交互。通过 JNI,你可以编写本地方法来

    2024年04月23日
    浏览(38)
  • Lua与C#交互初析

    项目是全Lua开发,导致的其中一个结果是会遇到lua的gc性能问题。而且相对于C#这种强类型语言,Lua因为其自由性,对于团队后期维护还是有一定的成本,不做好代码复审,相对不好维护。这个时候就需要我们自主了解Lua和C#交互的底层逻辑和实现原理,用以之后在lua测开发的

    2024年02月03日
    浏览(39)
  • Lua与C++交互(一)————堆栈

    什么是Lua虚拟机 Lua本身是用C语言实现的,它是跨平台语言,得益于它本身的Lua虚拟机。 虚拟机相对于物理机,借助于操作系统对物理机器(CPU等硬件)的一种模拟、抽象,主要扮演CPU和内存的作用。 虚拟机的主要职责就是:执行字节码中的指令,管理全局状态(global_stat

    2024年02月11日
    浏览(41)
  • Linux下Lua和C++交互

    lua(wiki 中文 官方社区:lua-users)是一门开源、简明、可扩展且高效的弱类型解释型脚本语言。 由于其实现遵循C标准,它几乎能在所有的平台(windows、linux、MacOS、Android、iOS、PlayStation、XBox、wii等)上运行。 在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来

    2024年02月16日
    浏览(34)
  • LUA 对象转excel

    因为是excel, 所以第一层要是数组,否则没有什么意义,即lua对象要是一个数组比较合理。这里使用开源的json.lua, 但是开源的,对于数字作下标的,或者是一个数组里,不同类型的key混合的情况无法转换,所以我进行了一定的改进,先进行了扫描判断是不是混合的key,是的话

    2024年01月18日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包