[基础] 代码语句与代码块 - 老司机也会翻车的地方
文章编号-AHK-J005
从一个诡异的案例讲起,代码如下。
您看完后猜猜是哪一个MsgBox会运行。
Haystack = abcdefghijklmnopgrs
Needle = abc
;# 检查变量是否包含指定的字符串.
IfInstring,Haystack,%Needle% {
MsgBox,% "The string was found " ;MsgBox_1
return
}
else
MsgBox,% "The string was not found " ;MsgBox_2
震惊:风格差异导致语义差异
我第一次看到这个案例的时候,我觉得一定是MsgBox_1运行,因为abc明显包含于Haystack,但是当我实际来测试的时候发现居然不是,而是提示我 Error: Unexpected "}" At line 4
看到提示之后,我瞪着眼看了好几次,但是发现括号的确是成双成对的,所以十分不解。
后来翻看案例,发现如果‘{’
不另起一行的话,程序就会匹配不到括号从而出现错误,而且这种现象只在某些命令中出现。
记得Java中有两种代码风格,分别是“行尾风格”和“次行风格”,简单举一个例子。所谓的“行尾/次行”指的是代码块中第一个花括号的位置。以下分别举出Java和AHK的例子。
//示例 AHK-J005-1
//Java代码
int a=0,b=1;
;# 行尾风格
if(a>b){
System.out.println("大于");
}
;# 次行风格
if(a>b)
{
System.out.println("大于");
}
;示例 AHK-J005-2
;# 行尾风格
IfInstring,Haystack,%Needle% {
Msgbox,包含
}
;# 次行风格
IfInstring,Haystack,%Needle%
{
Msgbox,包含
}
在Java中用哪种完全是依照读者的喜好,从语义上没有任何差异,语法上没有任何错误,只不过由于标准库里面的代码主要都是采用行尾风格,所以说基本上大家都喜欢这个,我也不例外。
但是在AHK中,绝大多数命令都是不能使用行尾风格的。
能够使用行尾风格的分别是:
函数的定义
异常的抛出与捕获(Try,Catch,Finally)
表达式形式的if-else
循环while,for,loop(普通)
小结:① 在Java中,风格的不同不会导致语义问题,但是在AHK中确会导致语义问题。② 在AHK中,有关于“函数以及类定义/表达式”的可以使用“行尾风格”,其他则不可使用。
深挖:导致该问题可能的原因是什么?
我猜测可能还是AHK的两套系统遗留下来的问题,命令系统中,参数是直接用逗号隔开的,如果在同一行,放着一个其他符号,那么就很难判断这个符号到底是属于参数还是命令,所以祖传的命令系统都是次行。
但是新的表达式系统,参数的列表被括号所包裹,所以就不存在这个问题,反而次行风格更受欢迎,因为它的可读性是更好的。
;示例 AHK-J005-3
;# 行尾风格
Haystack = abcdefghijklmnopgrs
Needle = abc
IfInstring,Haystack,%Needle% {
Msgbox,包含
}
;# 次行风格
IfInstring,Haystack,%Needle%
{
Msgbox,包含
}
if InStr(Haystack, Needle){
Msgbox,包含
}
if InStr(Haystack, Needle)
{
Msgbox,包含
}
小结:造成上述问题的原因很可能还是AHK颇有特点的“命令/表达式”二元结构。
语句:一个像空气一样的概念
语句简单来说就是程序运行的最小单位。
自从学习AHK以来,我就没有管过这个概念,在帮助文档中也极少会看到。但是当我拿起Java和AHK的代码时,却发现了差异,Java的每个语句的结尾必然是‘;’,所以在Java中,换号所起的主要作用就是增加可读性,如果你愿意,你可以把所有的内容写成几行。但是AHK中就不是,因为他们没有明显的语句分隔符。
很难想象语句会没有分隔,那么最大的可能性就是“分隔符是换行”,后来我在帮助文档中也查到了这一部分。
在Java中可以这么做,对于很短的句子来说,这样的表达显然更简洁。
//示例-AHK-J004
int Haystack=2,line=3,count=0;
Haystack+=2;line+=3;count++;
但是AHK中也并非完全不行,在某些情况下也是可以的(count1那一段)。
;示例-AHK-J005
count0=0 ,face=0,count++,face++
count1:=0,face:=0,count++,face++
MsgBox,% count0
MsgBox,% count1
MsgBox,% face
这被称为 “逗号(多语句) [v1.0.46+]”,它可以把多个表达式联合在一起使用,而且官方特别强调了,该方法对于运行效率的提高是很有帮助的。
小结:AHK中的语句分隔符就是换行本身,由于换行符本身是个透明的东西,所以在AHK中这个概念已非常弱化。其实,AHK也能够使用多语句,而且对提高效率有帮助。
方案:手动换行和延续片段
上面说过,在Java中换行的最大作用其实就是做代码的可读性提升,本身几乎是没有什么作用,但是AHK中却是非常重要的。
所以如果要手动换行的话,Java在大多数情况下,都可以直接按下回车键就解决,AHK该怎么办呢?
AHK给出了一些变通的方法,也就是只要在行首出现,除了“自增自减”之外的任何运算符,都看成“行延续”。在一些场景下,确实可以提升可读性,一种很常见的用法是,在那种很长的,“参数列表”中使用,比如:
;这个 TaskDialog 参数列表就非常长
TaskDialog(hParent = 0, sText = "", sButtons = "", iFlags = 0, sIcons = "", sRadios = "", sCallback = "", iWidth = 0, hNavigate = 0)
;直接堆叠的写法
iButtonID := TaskDialog(0, "软件升级||发现新版本" . "||本地版本 v" LocalVersion, "自动下载并更新到 v" LatestVersion . "`n点击立即更新" . "|手动下载最新版本 v" LatestVersion . "`n点击打开网站" . "|退出`nExit", 0x10, "GREY")
;行延续换行写法
iButtonID := TaskDialog(0
, "软件升级||发现新版本" . "||本地版本 v" LocalVersion
, "自动下载并更新到 v" LatestVersion . "`n点击立即更新" . "|手动下载最新版本 v" LatestVersion . "`n点击打开网站" . "|退出`nExit"
, 0x10
, "GREY")
另外,AHK而对于大批量的字符串进行了一下优化,叫做“延续片段”,主要是用于“长字符串”。
小结:为了解决手动换行符的问题,AHK简单粗暴的规定,只要在开头加入运算符,都算是行延续。
全文技术总结
- 在AHK中书写代码风格差异会直接影响语义,在调用命令时应特别注意要使用“次行风格”,不遵守将会导致程序出现严重错误。
- AHK中的换行其实是语句分隔符。但是在表达式系统中可以实现“多语句”并排,而且能够提高运算效率,有很大程度上提高了可读性,建议使用。
- AHK以除了 ++ 和 -- 外其他所有的表达式运算符开头的行,都会被自动的合并到前一行,在很多情况下,这会增加程序的可读性,建议使用。
- 如果遇到大批量字符串操作,建议使用“延续片段”。
End
心如止水是Java/AHK的持续学习者,很欢迎您来和我探讨Java/AHK问题。 QQ:2531574300 ^_^
更多文章:
[专栏] AHK程序设计 - SegmentFault 思否(优先持续更新)
[AHK经验] 动态调用本地库lib,必须显式声明
[基础] AHK函数对象系列-绑定方法对象
[基础] [GIF动图] 绕过中文输入法发送文本的3种方法
问题解答:
[问题解答] 示例不能运行吗? - 关于AHK程序设计系列文章示例问题的解释
版权声明:
该文章版权系“心如止水”所有,欢迎分享、转发,但如需转载,请联系QQ:2531574300,得到许可并标明出处和原链接后方可转载。未经授权,禁止转载。
文章版本:
v1_11月17日
v2_11月19日 增加有关于空格的简单说明
v3_12月15日
主要修改了关于“行延续”可读性问题的看法,并且增加了一个Example。
AHK版本:1.1.30.00