# 变量、常量

变量、常量指代码中使用合法的标志符、字面值(数值、字符串)来表示数据的对象。

## 一. 变量（ variables ）

在程序运行过程中，用来存储数据值并且其值能被改变的对象称为变量。变量的名称用字母、数字、中文字符、下划线等组成的[合法标识符](basic-syntax.html)来表示。  
  
- 变量名开始字符不能为数字。  
- 变量名包含中文时，中文字符前面不能有字母或数字。  
- 可以使用美元符号`$`作为变量名或变量名的第一个字符。  
  
建议遵循就近原则(Principle of Proximity) 在第一次使用局部变量之前定义该变量，这样做的好处让代码保持清晰的结构并增强可读性。  
  
### 1. 命名空间变量（ namespace variable ）、全局变量( global variable )

命名空间变量是属于一个[命名空间](namespace.html)的成员对象。  

变量的默认命名空间为 global 命名空间， global 命名空间的变量为全局变量。

可以使用 namespace 语句改变指定代码块的命名空间。

可以使用 self 关键字访问当前命名空间。使用 `..` 操作符访问 global 命名空间。

示例：

  
```aardio
//没有用 var 语句显式声明的变量，默认就是当前命名空间的成员变量

变量 = "字符串:普通变量";
变量 = "变量的值是可以改变的";

..varName = 123; //..varName 等价于 global.varName
```  

### 2. 局部变量（ local variable ） <a id="var" href="#var">&#x23;</a>


var 声明一个局部变量，作用域为当前语句块，以及被当前语句块所包含的语句块。var 语句声明的局部变量可选指定一个初始值，不指定初始值则默认为 null 值。

例如：

  
```aardio
var 局部变量;
局部变量 = 123;

var a,b,c = 1,2,3
console.log( a,b,c,局部变量 )
```  

请参考：[var 赋值语句](statements/assignment.html#var) [函数局部变量](function/definitions.html#var)  


## 二. 常量（ constants ） <a id="constants" href="#constants">&#x23;</a>


在程序运行过程中，用来存储数据值并且其值不能被改变的对象称为常量，常量赋为非 null 值以后就不能再更改值。  

常量名使用首字符为下划线且长度大于 1 个字节、小于 256 个字节的标识符表示，单个下划线符号仍然表示变量而非常量。

### 字面常量（ literal constants ）

字面常量是指以数值、字符串等字面值直接表示数据的常量对象。  
象`123`,`"abc"`这样的值被称之为字面值，并且这些值在运行时是不可更改的常量。


### 命名常量（ named constants ）<a id="named-constants" href="#named-constants">&#x23;</a>

aardio 中的命名常量都是在运行时初始化值。如果常量的值为 null，则可以赋值为非 null 值，之后就不能再修改值。常量重复赋于相同的数字或字符串等常量值会被忽略（不会报错），修改非 null 常量的值将会抛出异常错误。  

1. 命名空间常量( namespace constant ) <a id="namespace-constant" href="#namespace-constant">&#x23;</a>

    表对象（ table ）的成员名称如果首字符为下划线，并且长度大于 1 个字节并小于 256 个字节，则是一个只读成员（ readonly member ）。
    
    参考：[表的只读成员](datatype/table/_.html#readonly-member) 

    命名空间也是一个表对象（ table ），命名空间的只读成员我们称之为"命名空间常量"。
    
    "命名空间常量"与"命名空间变量"一样默认创建于当前命名空间 (self 命名空间 )。  
 
    示例：   

    ```aardio
    _const = 123; //初始化命名空间常量
    _const = 123; //没有修改常量，被忽略
    _const = 456; //出错，抛出异常：不能修改只读成员
    ```  
    
    要特别注意，命名空间或表的只读成员并不要求是合法标识符，例如： 

    ```aardio
    self["_ (不是合法标识符)"] = 1;
    self["_ (不是合法标识符)"] = 1234;//报错，不能修改常量
    ```  
    
    在对象的元表中指定元属性 `_readonly = false` 可禁用读成员保护，这样就可以自由修改名字以下划线开头的表成员。如果在表对象的元表中不设置 `_readonly` 则默认启用只读成员保护（所有名字以下划线开头的成员禁止修改非 null 值）。  
    
    如果元表中设置  `_readonly`  为任何非 null 值都会被强制转换为 false,  该值一旦设置以后即不可修改，如果希望启用只读成员保护，唯一的方法就是不设置该属性。  
    
    全局命名空间（ global 对象 ）将元属性 `_readonly` 设置为任何值都会被忽略，global 的只读成员保护总是启用状态。  

    参考：[_readonly 元属性](datatype/table/meta.html#_readonly)
  
  
2. 全局常量( global constant )  <a id="global-constant" href="#global-constant">&#x23;</a>


    "全局常量"特指全局命名空间只包含大写字母、数字或下划线的命名常量，同样要求首字符为下划线，并且长度大于 1 个字节并小于 256 个字节。

    全局常量的第一个非下划线字符必须是大写的英文字母（不能是数字或者中文字符）。

    "全局常量"可以直接在任何命名空间使用，并且不需要再添加表示全局命名空间的 `..` 前缀。

    "全局常量"不能与普通变量、局部变量同名，且无法被覆盖。例如 `var _GLOBAL ` 会报语法错误。  
    
    应避免滥用"全局常量"。 实际上滥用全局对象是不好的习惯，更好的方法是将它们放入适当的命名空间。如果理解了滥用全局对象会不知不觉增加程序的复杂度，意谓着您已经成为了一名有经验的程序员。  

    作为动态语言，大量的全局常量也会占用不必要的运行时资源。将值固定不变的全局常量改为利用智能提示的自动输入为字面常量并加上注释是一个不错的优化方案（如果可能需要调整常量值就不要这样做）。这种优化技术被用于 `libs\win\#DEFINE.aardio` (这不是一个库，放在库目录下仅仅是为了让扫描常量声明到智能提示数据库)。 

    `libs\win\#DEFINE.aardio` 中的部分智能提示配置演示：
    ```
    /**intellisense() 
    _TRUE=@1/*_TRUE*/
    _FALSE=@0/*_FALSE*/
    _NULL=@0/*_NULL*/
    end intellisense**/
    ```

    aardio 开发环境里提供将全局常量自动转换为上面这种智能提示模板的工具。在智能提示配置中，提示文本的第一个字符如果为 `@` 就表示这是一个自动完成的代码模板。例如我们在 aardio 编辑器中输入 _TRUE 时，可以利用智能提示的代码补全功能将 _TRUE 自动转换为 `1/*_TRUE*/`。

    所有系统 API 用到的全局常量，在 aardio 里首字符都会多一个下划线 `_`（除非首字符已经是下划线），这些全局常量都是大写的。　

3. 保留常量  <a id="reserved-constant" href="#reserved-constant">&#x23;</a>

    在合法标识符前加上 `::` 前缀，可将其转换为全局有效的保留常量。  

    保留常量的规则如下：
    - 保留常量也是全局有效的常量，属于全局命名空间的成员。
    - 保留常量一旦赋为非 null 值后同样不可修改。 
    - `::` 后面必须是合法的标识符，首个字符不能是小写字母或者下划线。
    - `::` 在编译期按编译顺序向后生效， 生效的保留常量即使省略 `::` 前缀仍然是保留常量。因为我们难以让不同文件的保持不变的加载与编译顺序，所以任何时候都不应当省略 `::` 前缀。
    - 保留常量不能与普通变量、局部变量同名，且无法被覆盖。应避免滥用保留常量，aardio 标准库只将少量的系统 DLL 模块、系统 API 函数定义为了保留常量。 

    常量仅能初始化赋值一次，对于相同的字符串或数值 —— 重复赋于相同的值会被自动忽略。如果是其他值则不能保证每次创建的值是相同的，为避免无意中修改常量值导致异常，可使用 `:=` 操作符赋值。  
    
    例如：  
    
    ```aardio
    ::Kernel32 := raw.loadDll("Kernel32.dll");
    ```  

    用 `a := b` 赋值等价于写  `a = a : b` ，这里的 `:` 为"逻辑或"操作符，等价于写  `a = a or b`。 