[中级] AHK元编程实战:用__Call()魔改默认基对象 v2

AB012-[中级] AHK元编程实战:用__Call()魔改默认基对象

在上一篇文章中,介绍了AHK元编程的基本概念和常用元函数 __Get(),其实 __Set()和它是大同小异,这里就不单独说了。下面主要是来说一下"默认基对象"。

默认基对象

什么是默认基对象?

AHK中有两种数据类型,分别是 StringObjectString 可以是直接量。

但其实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 , 有兴趣可以下载源码看看实现。

2019年01月14日 - 已经上线

关于隐藏的两个元函数

元函数除了这两个之外还有两个,不知道为什么在帮助文档上没有提,这里简单的说一下。

一个是__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程序设计系列文章示例问题的解释

版权声明:

该文章版权系“心如止水”所有,欢迎分享、转发,但如需转载,请联系QQ:3404624865,得到许可并标明出处和原链接后方可转载。未经授权,禁止转载。版权所有 ©心如止水 保留一切权利。

文章版本:

v1
v2:修复 Func 案例的错误(忘记检测aName,以及Func参数错误) 并且 增加注释6

AHK版本:1.1.30.00

心如止水

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值