变量
- 变量是什么
- 变量命名规则
- 变量类型详解
- 变量的容量和占用内存情况
变量是什么
顾名思义,变量就是会变的量,量就是多少的意思,所以再引申一点,变量就是变化多少的代名词。简单了解了变量的概念,下边我就讲一下变量的命名规则。
变量命名规则
首先说明一点,autohotkey语言变量命名规则很宽松,变量可以在脚本的任意位置读取或修改它们的内容. 除了在函数页面注明的情况,变量都是不需要声明的;使用它们的时候它们就产生了(每个变量初始为空)。用起来非常方便,但是看起来也会显得比较混乱,下边简单谈一下变量的命名:
- 不能与表达式运算符冲突,因为单词 AND , OR 和 NOT 作为表达式的运算符使用, 所以通常不应该把它们用作变量名称. 在表达式中使用这样的名称会无法正确计算.
- 不能与函数名冲突,跟函数名冲突后,会给阅读者造成很大困扰,同时也会引发一些运行错误。
- 不能与内置变量冲突,冲突后系统会当作内置变量处理。
- 不能与环境变量冲突。
几点提示:
- 变量名不区分大小写 (例如, CurrentDate 等同于 currentdate ). 变量名可以含有多达 253 个字符, 并且可以由字母, 数字以及后面的标点组成: # _ @ $
- 考虑到命名的惯例, 通常在命名变量时最好仅使用字母, 数字和下划线 (例如: CursorPosition , Total_Items 和 entry_is_valid ). 这样的风格可以让熟悉其他计算机语言的人更容易理解您的脚本. 而且, 如果您在 AutoHotkey 和其他语言中使用相同的风格, 您会发现能更容易重新读懂自己的脚本.
- 尽管变量名可以完全由数字组成, 但通常这样的名称仅用于 传入的命令行参数 . 这样数值名称的变量不能用在 表达式 中, 因为它们会被看成是数字而不是变量.
变量分类
AutoHotkey 中没有明确的变量类型.我根据经验总结,ahk的变量类型有以下几种分法:
按照数据类型划分有
- 数字型变量
数字型变量分为两种整型和浮点型,所谓整型就是整数,所谓浮点型就是带小数点的数,举个例子:
a=18
b=1.8
a就是整形,b就是浮点型
- 文本型变量,字符串
a=河许人
- 布尔型变量,true/flase,on/off等
a=true
b=off
然而, 只包含数字 (可以含有小数点) 的变量进行数学运算或比较时, 会被自动转换为数值. (为了提高性能, 在内部会对数字进行缓存以避免与字符串之间的转换.)
按照作用域和生命周期划分
分为全局变量、局部变量和静态变量,谈到这里就涉及到两个概念:作用域和生命周期。
这是两个完全不同的概念,虽然很多时候相互关联。作用域是作用在空间上的,比如一个变量在代码的哪些行能访问,哪些行不能访问。而生存期是作用在时间上的,比如一个变量的值在函数返回后是否失效。
全局变量
全局变量比较好理解,如果一个变量是全局变量,那么程序中的所有代码都可以访问到这个变量(除非存在同名的局部变量或者静态变量)。全局变量用 global 定义。
看一个例子。
a := 1 global b := 2 c := 3 fun() { ; a 不是全局变量,访问不了,弹出空字符串 MsgBox, % a ; b 是全局变量,弹出 2 MsgBox, % b ; 在函数里也可以将 c 变成全局变量 global c ; 弹出 3 MsgBox, % c }
注意代码里的 a 并不是全局变量,虽然它的作用域要比函数里的局部变量要大,在所有文件的函数外都可以访问,但在函数内它是不能被访问到的,这算是一个特例。
局部变量
在函数里使用的变量通常是局部变量。
fun() ; a 并不是全局变量,弹出空字符串 MsgBox, % a ; b 是全局变量,弹出 2
MsgBox, % b
fun()
{
a := 1 global b := 2
}
注意这里 b 是在函数里定义的全局变量,但不管是在什么地方定义的,在其他地方都可以访问到。
静态变量
全局变量和局部变量的作用域和生存期都不一样。全局变量的作用域和生存期都是全局的,局部变量的作用域是在函数内部,生存期是从函数开始执行到函数返回。
但还有一种比较特别的变量是静态变量。
; 弹出 1 1(第一次)
fun()
; 弹出 1 2(第二次)
fun()
fun()
{
a := 1
static b := 1
MsgBox, % a " " b
a++
b++
}
a 就是普通的局部变量,因为每次执行 a 都会被初始化为 1,所以两次运行 fun 函数时 a 的值都是 1。但 b 是一个静态变量(使用 static 定义)。静态变量的作用域和局部变量一样,只能在函数内访问。但生存期和全局变量一样,也就是说一个静态变量定义后,它的值会一直有效,即使函数已经返回了。所有第二次运行 fun 函数后,b 的值已经是 2 了。
使用场景
那么什么分别在什么情况下使用三者呢?
没有特殊需求的场景,都应该使用局部变量,这也是默认的情况。
如果一个变量是需要全局有效的,那么使用全局变量。但全局变量会导致代码的耦合度比较高,不方便维护,所以尽量少用。有些看似需要使用全局变量的场景,其实使用函数的参数传递更合理。
如果某个局部变量需要只初始化一次(一般情况是因为初始化有开销,这是主要的场景),或者需要保留上次运行的结果(这会导致代码容易滋生 bug,并且难于测试,尽量少用),那么需要将这个局部变量修改成静态变量。
按照形式划分
可以分为普通变量、内置变量、环境变量,普通变量没什么好解释的了,下面详细讲一讲内置变量和环境变量。
内置变量
内置变量就是说这些变量名称已经内置到程序中了, 可以在任何脚本中引用. 除了 Clipboard、ErrorLevel和命令行参数, 其他变量都是只读的; 即它们的内容无法在脚本中直接修改.有哪些内容呢?
•特殊字符: A_Space, A_Tab
•脚本属性: 命令行参数, A_WorkingDir, A_ScriptDir, A_ScriptName, (...更多...)
•日期和时间: A_YYYY, A_MM, A_DD, A_Hour, A_Min, A_Sec, (...更多...)
•脚本设置: A_IsSuspended, A_BatchLines, A_TitleMatchMode, (...更多...)
•用户空闲时间: A_TimeIdle, A_TimeIdlePhysical
•GUI 窗口和菜单栏: A_Gui, A_GuiControl, A_GuiEvent, A_EventInfo
•热键, 热字串和自定义菜单项: A_ThisHotkey, A_EndChar, A_ThisMenuItem, (...更多...)
•操作系统和用户信息: A_OSVersion, A_ScreenWidth, A_ScreenHeight, (...更多...)
•杂项: A_Cursor, A_CaretX, A_CaretY, Clipboard, ClipboardAll, ErrorLevel
•循环: A_Index, (...更多...)
关于这些内置变量如何使用,在下一课内置变量专题中会详细讲解。
环境变量
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程。
环境变量由操作系统维护. 在命令提示符中输入SET并回车后, 您可以看到环境变量列表.
脚本中可以使用 EnvSet 创建新的环境变量或改变现有环境变量的内容. 但是, 这样的添加和改变都是私有的; 它们不会被系统的其他部分看到. 一个例外是当脚本使用 Run 或 RunWait 运行程序时 (甚至是另一个脚本): 这样的程序会继承其父脚本的环境变量的副本, 包括私有的那些.
在 v1.0.43.08+, 推荐在所有新脚本中使用以下方式获取环境变量, 例如 Path:
EnvGet, OutputVar, Path
关于环境变量的操作,当前课程涉及较少。我会在环境变量控制那一课进行详细阐述,这里略讲。
**变量的容量和占用内存
•每个变量最多可以含有64MB的文本(使用#MaxMem可以突破这个限制).
•当赋值给变量比当前更长的内容时, 会自动分配额外的系统内存给这个变量.
•通过赋值为空可以释放大变量占用的内存, 例如 Var := "".
•脚本可以创建的变量数量没有限制. 程序设计用来支持至少几百万的变量而不会出现明显的性能下降.
•接受数值输入的命令, 函数和表达式通常可以支持 15 位的浮点数精度. 对于整数, 可以支持 64 位有符号整数, 其范围从 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF). 此范围外的任何整数不受支持, 并可能产生错误的结果. 与之相比, 整数的算数运算结果超出此范围时会产生溢出 (例如 0x7FFFFFFFFFFFFFFF + 1 = -0x8000000000000000).
**