_AB012-[中级] AHK元编程实战:用_Call()魔改默认基对象
在上一篇文章中,介绍了AHK元编程的基本概念和常用元函数
__Get()
,其实__Set()
和它是大同小异,这里就不单独说了。下面主要是来说一下"默认基对象"。
默认基对象
什么是默认基对象?
AHK中有两种数据类型,分别是 String
和 Object
,String
可以是直接量。
但其实String的本质也是 Object
,只不过他也是一个系统内置的 Object
罢了。
更改String的实际需求
由于AHK中 String
并没有内置方法,所以很多时候会非常的不方便。
比如当我们想获取 String
长度的时候,我们需要StrLen(Str)
,其实最符合直觉的办法应该是Str.Length
。
当然还有很多我们需要的方法没有提供,比如最基本的Str.toArray
(转为字符数组),Str.CharAt
(提取某一位置的特定字符)等等等。
那现在我们就来给 String
加入这些实用的方法,下面将会以最简单的Str.Length
为例子演示。
魔改
获取默认基对象
String
的基对象可以由任何字符串获取,这个是非常好理解的,String
是一定是 StringClass
对象,所以可以这么获取"".base
。
要注意的是,base 本身不能被替换,因为如果被替换,那么 String
的语法就全都完蛋了。[注1]
方案1:替换 base 成员
base
里面的元函数成员是可以被我们替换的,我们想实现Str.Length
这种形式,需要对__Get()
进行替换,那么我们该怎么实现这个替换呢?[注2]
想一下上一节讲到的"对象协议",()
这个语法对应的协议是什么?
很明显就是__Call()
,那么什么东西含有__Call()
?
只要能被()
语法所调用的都可以是含有__Call()
的。
回顾一下之前学过的内容,大概有这么几种可能,首先是 Func
对象,然后是 ObjBindMethod
对象,还有 MethodObject
。[注3]
其实 ObjBindMethod
我们并不需要,因为我们现在可以自定义,ObjBindMethod
只是在我们不能获取Object
的时候使用的,现在能获取,显然就用不到;另外我们需要预留出参数使用,我们并不知道现在的参数是多少,所以更不能进行Bind
。
Func对象替换
这里提一句,这个办法官方叫做"伪属性","属性"之前我们提到过,其实"属性"可以看做
__Get()
和__Set()
的语法糖。
这样思路就非常简单了,我们先定义一个函数,之后使用 Func(FuncName)
获取一下。
但是这里要特别注意的是,我们定义函数的时候,需要给 对象 留出一个参数。
我们先来看一下之前的例子。
MateObj:=new Mate()
DeBugDeepPrintln(MateObj[1,2],"MateObj[1,2] >>> ")
Class Mate{
__Get(aName,Para*){
if (aName=1){
return "A"
}
}
}
你可以看到之前的例子,第一个参数是aName
,其实还有一个隐含的参数没有写出来,这个参数就是Object
,方法必须从属Object
,当其被 extends 使用的时候,这个Object
就是this
,直接被使用的时候Object
就是ClassObject
本身。[注4]
但是当我们直接使用 函数 的时候,并没有从属于Object
,所以我们必须手动把这个参数给加上去。
StringGet(Str,aName){
if (aName="length")
return StrLen(Str)
else
return
}
theFuncObj:=Func("StringGet")
"".base.__Get:=theFuncObj
theLen:="I Love You".length
运行的结果就是 theLen=10
。
但是这个方法的缺点也很明显,要通过Func()
获取对象,非常不方便,那你想定义多个方法的时候是无法实现的[注6],因为 字段 就那么一个,被覆盖就没有了。
方案2:extends 方案
还有一个方案就是利用 extends
,虽然我们不可以改动 base,但是我们可以改 base 的 base ,也就是利用 extends。[注5]
"".base.base:=StrBase
theLen:="I Love You".length
DeBugDeepPrintln(theLen,"theLen >>> ")
class StrGetBase{
__Call(aStr,aName,aParams*){
if(ObjHasKey(this,aName)){
OutPut :=this[aName].Call(aStr)
return OutPut
}
else
return ""
}
}
class StrBase{
class __Get extends StrGetBase{
length(){
return StrLen(this)
}
;.............
;.............
}
}
这个方法的好处就是显而易见了,后面可以跟无穷无尽的方法,你加多少个方法都可以。
之后我会把自己用的比较多的 String 方法 上架 BeanLib , 有兴趣可以下载源码看看实现。
关于隐藏的两个元函数
元函数除了这两个之外还有两个,不知道为什么在帮助文档上没有提,这里简单的说一下。
一个是__Init
,还有一个是 __NewEnum
,在帮助文件上,几乎找不到它们的踪迹(只有两处略微提到一句)。
第一个的意思是"initialize",翻译为"初始化",也就是在new
之前调用的。
第二个就比较容易理解,就是 for
语法的元函数,调用枚举器。
我就不多说了,有兴趣查英文资料吧,中文没有。当然如果你会C++
,直接看源码也行。
SciTE自动完成列表中的元函数 当然还有本人英语渣,正在努力,看你们的啦,我啃不动。发现了啥好东西,别藏着掖着啊,做人要厚道。
__New
和__Delete
,不过好像想不出什么用处来,帮助文件上,其实也没有提到他们作为"元函数"的用例。
最后提一嘴__Set()
想半天觉得这个__Set()
还是有个地方需要说一下的,__Set()
的设计需要遵循 return value
,也就是参数value = return 值。
为什么有这个要求呢?
是因为预制的对象都是这么搞的,if(b=v1:=v2)
这种用法很常见,如果要搞特例的话,别人用起来是很蛋疼的。
元编程还有什么用?
在第一篇文章中,我提到过,"我不知道有啥用",其实我已经用这个方法改 String 很久了,连我自己都忘了,今天写第二篇文章才想起来。
至于其他的用法,应该会有很多吧,去英文网站上看了一下发现了这个精辟的帖子。
里面货很多,元函数的用法,只有你想不到,没有他做不到。
有空的话你可以搬出点东西来自己用,然后顺手整理一下,投稿到 BeanLib ,非常欢迎。
注释
[注1] : 帮助文件中并没有解释, base
不能被直接替换的原因,但是我认为这个解释是显而易见的。
[注2/3] : 在AHK中,Class
内的方法是可以直接用 Call()
调用的,而且他们是占据字段(Field)的。
比如,如果Func
是你定义的一个函数,你可以再给Func赋值,比如Func:="ABC"
,Func
函数是不会被覆盖的;但是Func
如果是 方法 ,那么就会被直接给覆盖,这个和 Class 是一个原理。
官方没有给他们起一个名字,显而易见他们叫做MethodObject(方法对象)
是非常合适的,因为 官方把同样占据 字段 的 Class 叫做 Class objects(类对象)
。
[注4] Class/Method 本身就是对象, Method 就不存在是否 static 的问题,都可以调用。
[注5] extends 翻译成"继承"比较多,实际上它的原意是"扩展"/"扩增"。B extends A,意思就是"B 从 A 延伸而来",换一种说法就是"B 是 A 的基础",所以B.Base:=A
,和A extends B
是一个意思。
[注6] 当然你可以通过检测aName的方法间接实现,但是方法内不能有方法,也就是说你所有的代码都要挤在一个方法里面,这个事情有多蛋疼想想就知道,我就不多说了。
End
心如止水是Java/AHK持续学习者,欢迎您来和我探讨Java/AHK问题 _
GitHub
欢迎您来访问我的GitHub,在这里您可以看到我的代码分享,关注我的最新动态。
欢迎给 新生的 BeanLib 投稿,每一位贡献者的名字都将被铭记。
更多文章:
- [专栏] AHK程序设计 - 简书(优先持续更新)
- [基础] [GIF动图] 绕过中文输入法发送文本的3种方法
- [基础] AHK函数对象系列-绑定函数对象v3
- [基础] AHK函数对象系列-绑定方法对象
- [基础] 在AHK中实现函数重载的效果
- [基础] AHK函数对象系列-对象属性与数据域保护v2
- [中级] AHK元编程初步:对象协议和__Get()
问题解答:
[问题解答] 示例不能运行吗? - 关于AHK程序设计系列文章示例问题的解释
版权声明:
该文章版权系“心如止水”所有,欢迎分享、转发,但如需转载,请联系QQ:3404624865,得到许可并标明出处和原链接后方可转载。未经授权,禁止转载。版权所有 ©心如止水 保留一切权利。
文章版本:
v1
v2:修复 Func 案例的错误(忘记检测aName,以及Func参数错误) 并且 增加注释6
网友评论