操作符与表达式 2 (2.014)

(无版本差异)

17 一元表达式

后缀表达式
& 一元表达式
++ 一元表达式
-- 一元表达式
* 一元表达式
- 一元表达式
+ 一元表达式
! 一元表达式
~ 一元表达式
( 类型 ) .标识符
New表达式
Delete表达式
Cast表达式
New匿名类表达式


17.1 New 表达式
New表达式:
New参数 类型 [ 赋值表达式 ]
New参数 类型 ( 参数列表 )
New参数 类型
New参数 类参数 基类列表
可选的
{ 多个声明定义 }
New参数:
new ( 参数列表 )
new ( )
new
类参数:
class ( 实参列表 )
class ( )
class
实参列表:
赋值表达式
赋值表达式 , 实参列表

New表达式 用来在垃圾回收堆(默认情况)上分配内存,或者使用类指定的分配器分配内
存。

在为多维数组分配内存时,声明按照同读取后缀数组声明顺序相同的顺序读取声明。
char[][] foo; // 字符串动态数组
...
foo = new char[][30]; // 分配 30 个字符串数组
上面的分配也可以写成这样:
foo = new char[][](30); // 分配 30 个字符串数组
要分配嵌套的数组,可以使用多重参数:
int[][][] bar;
...
bar = new int[][][](5,20,30);

这个等同于:
bar = new int[][][5];
foreach (ref a; bar)
{
a = new int[][20];
foreach (ref b; a)
{
b = new int[30];
}
}
如果有一个 new ( 实参列表 ),那么这些参数在大小参数之后被传递给类或结构特有的分配
函数。

如果 New表达式 被用来作为函数里带有 scope 储存类别的局部变量的初始值,并且实参
列表(传递给 new 的)为空,那么在堆栈上分配实例,而不是在堆实例进行分配,或者使
用类特有的分配器。

17.2 Delete 表达式

delete 一元表达式
如果 一元表达式 是一个类对象引用,而且该类有析构函数,那么该析构函数就会对于该对
象实例被调用。

其次,如果 一元表达式 是一个类对象引用,或者是一个指向结构实例的指针,并且类或结
构已经重载了操作符 delete,那么操作符 delete 就会针对访类对象实例或结构实例被调用。

否则,垃圾回收器被调用来立即释放针对该类实例或结构实例分配的内存。如果垃圾回收没
有被用来为该实例分配内存,那么就会导致未定义行为发生。

如果 一元表达式 是一个指针或动态数组,那么垃圾回收器会被调用来立即释放内存。如果
垃圾回收没有被用来为该实例分配内存,那么就会导致未定义行为发生。

指针、动态数组或者引用在完成 delete 操作后被设置成 null。

如果 一元表达式 是在堆栈h上分配的变量,则访类析构函数会针对该实例被调用(如果有
必要的话)。垃圾回器以及任何类的重新分配器都不会被调用。


17.3 Cast(类型转换) 表达式
Cast表达式:
cast ( 类型 ) 一元表达式
Cast表达式 将 一元表达式 转换到指定的 类型。
cast(foo) -p; // 将 (-p) 转换到类型 foo
(foo) - p; // 从 foo 减去 p

任何对于派生类引用的类型转换完成时,都会执行运行时检查以确保它是真的向下转换的。
如果不是那样,则结果就为 null。注意:这个等同于 C++ 里的 dynamic_cast 操作符。
class A { ... }
class B : A { ... }
void test(A a, B b)
{
B bx = a; // 错误,需要类型转换
B bx = cast(B) a; // 如果 a 不是 B 类型,bx 就为 null
A ax = b; // 不需要类型转换
A ax = cast(A) b; // 不需要向上类型转换的运行时检查
}

如果想要检测一个对象 o 是否是类 B 的一个实例,可以使用类型转换:
if (cast(B) o)
{
// o 是 B 的一个实例
}
else
{
// o 不是 B 的一个实例
}

虽然将浮点文字从一种类型转换成另一种类型会改变它的类型,但是在内部它仍然被保留了
完整的类型,为的是常量折叠(constant folding)。
void test()
{
real a = 3.40483L;
real b;
b = 3.40483; // 文字没有被截断成双精度数(double precision)
assert(a == b);
assert(a == 3.40483);
assert(a == 3.40483L);
assert(a == 3.40483F);
double d = 3.40483; // 当给变量赋值时截断文字
assert(d != a); // 因此它不再一样
const double x = 3.40483; // 赋值给常量不会
assert(x == a); // 被截断,如果初始值是可见的话
}

把一个值 v 类型转换成一个结构 S,这样的操作当值不是同类型的结构时,就等同于:
S(v)


18 后缀表达式
后缀表达式:
基本表达式
后缀表达式 .标识符
后缀表达式 .New表达式
后缀表达式 ++
后缀表达式 --
后缀表达式 ( )
后缀表达式 ( 实参列表 )
索引表达式
分割表达式

19 索引表达式

后缀表达式 [ 实参列表 ]
后缀表达式 会被计算。 如果 后缀表达式 是一个静态或者动态类型的数组表达式,那么符
号“$”就会被设置成该数组里元素的个数。 如果 后缀表达式 是一个 表达式元组,那么符
号“$”就会被设置成该元组里元素的个数。 对于 实参列表 的求值会创建新的声明作用
域,而且“$”只出现在该作用域中。
如果 后缀表达式 是一个 表达式元组,那么 实参列表 必须只有一个参数组成,而且必须
是静态可求值到一个整型常量。整形常量 n 然后选择第 n 个表达式(位于 表达式元组
里),它就是 Index表达式 的结查。如果 n 超出 ±í´ïʽ元组 的范围,则会出现一个错
误。

20 分割表达式
后缀表达式 [ ]
后缀表达式 [ 赋值表达式 ..赋值表达式 ]

后缀表达式 会被计算。如果 后缀表达式 的类型为静态或者动态数组,会隐式地声明变量
length(以及特殊符号 $),并将数组的长度赋给它。对于 赋值表达式..赋值表达式 的求
值会创建新的声明作用域,而且 length(以及 $)只出现在该作用域中。

第一个 赋值表达式 被规定包含分割块的下界, 而第二个 赋值表达式 则超出上界。表达
式的结果就是 后缀表达式 数组一个分割部分。
如果使用了 [ ] 形式,则该分割部分就是整个数组。

分割部分的类型是动态数组,而此动态数组元素的类型就是 后缀表达式 的元素类型。
如果 后缀表达式 是一个 表达式Tuple,那么分割部分的结果就是一个新的 ±í´ïʽ元组
(由上界和下界组成),此新的表达式必须静态求值成整型常量。如果这些边界超出范围,
就会出一个错误。


你可能感兴趣的:(表达式)