# 赋值语句

## 一. 普通赋值语句

赋值语句改变一个变量的值。  
赋值语句不能作为表达式使用，也不能作为表达式的一部分使用。  
赋值语句必须是独立的语句，普通的赋值语句（在循环语句中初始化循环变量除外）不能作为其他语句的一部分，例如 `v = v2 = 100` 的写法是错误的。  
  
### 赋值

示例: 

```aardio
a = 120;
```

赋值基本规则：

- 如果将一个变量赋值为 null 等同删除这个变量。 
- table,cdata,function 类型的数据在赋值时并不会创建新的值而只是添加一个引用(即新变量仍然指向同一个对象)。
- 将数据作为函数的参数时也会进行赋值操作，作为参数 table,cdata,function 同样是按引用传递的。
- 相同字符串（ string 类型 ）也会引用同一块内存，但修改字符串时总是会创建新的对象，所以改动一个字符串不会影响另一个字符串。

### 多重赋值（Multiple Assignment） 

示例: 

```aardio
a,b,c = 1,2,3;  
```

以上的写法等效于：

```aardio
a=1;
b=2;
c=3;
```

多重赋值时，执行 **多退（丢弃）少补（ null 值）** 规则。
右边的操作数如果多于左边的变量数目则丢弃多余的值，右边的操作数不足则填充为 `null` 值。  

示例: 

```aardio
a,b,c = 0; 
```

上面的代码执行后 a 等于 0 , 而 b,c　的值都是 null。

如果一个函数有多个返回值时，也可以使用多重赋值的方法，例如：  

示例: 

```aardio
var a,b,c = table.unpack( { 1 ; 2 ; 3 } )
```

### 使用 var 语句定义局部变量 <a id="var" href="#var">&#x23;</a>

使用局部变量有两个好处: 

1. 避免命名冲突 
2. 访问局部变量的速度比访问全局变量（或当前命名空间变量）快。

请参考： 

- [局部变量](../variables-and-constants.html#var)
- [函数局部变量](../function/definitions.html#var)

#### 声明局部变量

局部变量需要用 var 语句声明，例如：

```aardio
var a; //声明局部变量，默认为 null 值
var b = 2; //声明局部变量并指定初始值
```

可以在一个 var 语句中声明多个变量，支持以下三种写法：

1. 	多重赋值（Multiple Assignment）

例如：`var a,b,c = 1,2,3;`

初始值列表可省略，数目不要求与声明的变量个数相同，执行多退（丢弃）少补（ null 值）规则。

例如：`var a,b,c = 1;` 运行后 a 的值为 `1`, b,c 的值为 `null`。

2.   声明列表（Comma-separated declaration list ）

例如: `var a = 1, b = 2, c` 

如果在 var 语句中 **对首个变量赋值** 则 aardio 将其视为声明列表，其他变量可省略初始值。

3. 分组声明（Grouped Declarations）

例如  `var(a=1;b=2;c=3)`

如果在 var 关键字后跟一对括号，则括号内可包含任意多个省略 var 关键字的语句，语句间必须用分号隔开。

实际是包含多个省略 var 关键字的语句，必须用分号作为语句分隔符。

分组声明内部也可以放省略 var 的多重赋值与声明列表语句，例如：

```aardio
var(
  a,b,c = 1,2,3;
  a = 1, b = 2, c 
)
```

> aardio 允许用 `const` 关键字代替 `var` 关键字，但 `const` 声明的是局部变量，没有强制的只读约束。声明具有只读保护的常量请参考 [常量](#constants)

#### 局部变量的作用域

- 局部变量拥有块级作用域
- 局部变量必须先声明后使用，没有局部变量提升陷阱（Local Variable Hoisting）

局部变量拥有块级作用域，并且必须先声明后使用。

```aardio 
if( true ){
    callBeforeDefinition();  // 错误：callBeforeDefinition 为 null
    var insideBlock = function(){};
}

var callBeforeDefinition = function(){};
insideBlock();  // 错误：insideBlock 为 null
```


### 使用赋值语句定义变量、常量

没有用 var 语句声明过的标识符默认为当前命名空间的常量或变量。

一个从未赋值的常量或变量默认值为 null。

当前命名空间的成员名称如果首字符为下划线，并且长度大于 1 个字节并小于 256 个字节，则是一个命名常量，否则为变量。

参考: [变量与常量](../variables-and-constants.html)

命名空间只包含大写字母与下划线的命名常量为 [全局常量](../variables-and-constants.html#global-constant)，全局常量在所有命名空间都可以直接使用，不需要再添加表示全局命名空间的 `..` 前缀。 

示例：

```aardio
//将变量声明为当前命名空间下的成员变量
value = 100;

//以下划线开始的成员常量，赋为非 null 值以后就不能再更改值。
_value = 100; 

//以下划线开始的全局常量，赋为非 null 值以后就不能再更改值。
_VALUE = 100; 

//使用::操作符定义的全局常量，只能赋值一次 
::Value = 100;
```

### 使用赋值语句删除变量

将一个变量赋值为 null，删除这个变量。例如：  

```aardio
value = null;
```

## 二. 复合赋值语句

`a = a + b` 可以写成 `a += b`。

所有二元操作符都可以按上述规则书写。  
  
例如：

```aardio
a -= b;  
a *= b;  
```

复合赋值操作符不能包含空格，如 `a + = b;` 是错误的 ![](../../icon/error.gif)，正确的应当是 `a += b;`![](../../icon/ok.gif)  

复合赋值的几个特例：

- 初始化赋值

  初始化赋值使用复合赋值语句：`A := c ` 。

  `A := c ` 等价于 `A = A:c ` 。如果 `A` 为 null 空值，则将 `c` 赋值给 `A`。

  定义命名常量时，为避免重复赋值，通常使用会初始化赋值语句。  
    
  参考: [命名常量](../variables-and-constants.html#named-constants)

- 条件赋值

  示例： 

  `str ?= string.lower(str) `
    
  上面的复合赋值语句等价于： 

  `str = str and string.lower(str)` 
    
  如果 str 不为 null 空值，则执行后面的赋值语句。

  其语义如下：

  ```aardio
  if(str != null){
      str = string.lower(str)
  }
  ```  

  这样可以避免 str 为null 空值时，string.lower 抛出错误。如果 str 为空，则等号右侧的语句根本不会执行。  

## 五. 自增自减赋值

自增语句 `a++` 等价于 `a += 1`。  
自减语句 `a--` 等价于 `a -= 1`。

要特别注意在 aardio 中语句不是表达式，自增自减语句同样也必须是独立语句不能作为表达式使用。