这一章1.028和2.014相同
1 基本数据类型
2 派生的数据类型
• 指针(pointer)
• 数组(array)
• 关联数组
• function
• delegate
3 自定义数据类型
• alias
• typedef
• enum
• struct
• union
• class
4 基类型(Base Types)
5 指针转换
D 允许指针到非指针、非指针到指针的转换;但是,决不要对指向由垃圾回收程序所分配的
数据的指针进行此类操作。
6 隐式转换
隐匿转换用于在需要的时候自动完成类型转换。
类型定义(typedef)或枚举(enum),可以隐式地转换到它的基类型,但在其它环境就需要显示转换。 A literal can be implicitly converted to a typedef.
例如:
7 整数提升
整数提升可以转换下列类型:
如果类型定义或枚举的基类型时是上面左列中的某种类型,那么也会转换到右列中相应类
型。
8 常见的算术转换
常见的算术转换会将二元运算符的操作数转换为通用的类型。这个操作数必须已经是算术类
型。下面的规则将会按顺序应用:
1. 如果操作数是实型,那么其它的操作数将被转换成实型。
2. 如果操作数是双精度数,那么其它的操作数将被转换成双精度数。
3. 如果操作数是浮点数,那么其它的操作数将被转换成浮点数。
4. 否则才对每个操作数进行整数提升,步骤如下:
1. 如果两个操作数类型相同,则无需再作转换。
2. 果两个操作数都是有符号或无符号的,较小的类型会被转换为较大的类型。
3. 如果有符号的类型比无符号的类型大,无符号的类型会被转换为有符号的类型。
4. 否则有符号的类型会被转换为无符号的类型。
如果有一到两个操作数类型在经上面的转换后变成了类型定义或枚举,则最终类型是:
1. 如果操作数是相同类型,则结果也就是该类型。
2. 如果其中一个操作数是类型定义或枚举,而另一个的类型是类型定义或枚举的基类
型,则结果就是基类型。
3. 如果两个操作数是不同的类型定义或枚举,但有相同的基类型,则结果就是基类型。
整型值不能隐式地转换成其它在整数提升后不能代表整数位模式的类型。例如:
浮点类型不能隐式转换成整数类型。
浮点复数类型不能隐式转换成浮点非复数类型。
浮点虚数类型不能隐式转换成浮点、双精度或实型类型。浮点、双精度或实型类型不能隐式
转换成浮点虚数类型
9 bool
bool(布尔类型)是一种只有一个字节大小的类型,它仅能存放 true 或 false,即真或假。
只能接受布尔类型操作数的操作符有:
& | ^ &= |= ^= ! && || ?:.
一个布尔值可以隐式地转换成任何整数类型: false 变成 0,而 true 变成 1。
单独的数字 0 和 1 可以隐式地转换成相应的布尔值 false 和 true。
测试一个表达式的布尔值即意味着:在算术类型时,测试 0 或!=0;
而测试 null 或 !=null 则是表示浮点或引用运算。
10 委托
在 D 中没有成员指针(pointers-to-members),但它支持一个更为有用的概念,即委托
(delegates)。委托是一个由两部分数据组成的聚集:一个是对象引用,另一个是函数指针。
当调用函数时,对象引用就形成 this 指针。
委托的声明同函数指针的声明很相像,区别就是使用关键字 delegate 来替代 (*) ,并且随后紧跟着标志符:
C 风格的声明函数指针的语法也被支持:
委托的初始化同函数指针一样:
委托不能用静态成员函数或者非成员函数初始化。
委托同函数指针一样调用:
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
属 性 (Properties)
每种类型和表达式都有可以查询的属性(Properties):
1 所有类型的属性
2 整数类型的属性
3 浮点类型的属性
4 .init 属性
.init 产生一个常量表达式,其值为默认初始值。如果应用到某个类型,其值为该类型的默认初始值。如果应用到某个变量或域,其值为这个变量或域的默认初始值。
例如:
5 .stringof 属性
.stringof 会生成一个常量串,此字符串是它有前缀的“源表示(source sentation)”。
如果被应用到某个类型,那么它就是那种类型的字符串。如果被应用到一个表达式,那么它就是那个表达式的“源表示(source representation)”。
语义分析并不会处理那个表达式。
例如:
6 类和结构的属性
属性是成员函数,但在语法上被看作是域。属性可以被读写。属性可以通过调用一个不带实
参的方法来读取;再通过调用一个带有实参的方法来进行写入,其中的实参就会成为该属性
的值。
简单的属性可以表示成:
使用方法:
如果没有读方法就意味着属性是只写的。如果没有写方法就意味着属性是只读的。可以有多
个写方法共存,用正常的重载规则来决定采用哪个函数。
在其他方面,这些方法同其他的方法都是相同的。它们可以是静态的、拥有不同的链接方
式、被重载、被取地址等等。
注意:目前属性不能作为运算符 op=、++ 或 -- 的左值。
。。。。。。。。。
1 基本数据类型
关键字 描述 默认初始值(.init)
void 无类型 -
bool 布尔值 false
byte 8位有符号数 0
ubyte 8位无符号数 0
short 16位有符号数 0
ushort 16位无符号数 0
int 32位有符号数 0
uint 32位无符号数 0
long 64位有符号数 0L
ulong 64位无符号数 0L
cent 128位有符号数(预留将来使用) 0
ucent 128位无符号数(预留将来使用) 0
float 32位浮点数float.nan
double 64位浮点数double.nan
real 硬件支持的最大的浮点大小 real.nan
(实现提示:在Intel的CPU上是 80 位)
ifloat 浮点 虚 数 float.nan * 1.0i
idouble 双精度 虚 数 double.nan * 1.0i
ireal 实型 虚 数 real.nan * 1.0i
cfloat 带两个浮点值的复数 float.nan + float.nan * 1.0i
cdouble 双精度复数 double.nan + double.nan * 1.0i
creal 实型复数 real.nan + real.nan * 1.0i
char 8位无符号 UTF-8 数 0xFF
wchar 1 6位无符号 UTF-16 数 0xFFFF
dchar 32位无符号 UTF-32 数 0x0000FFFF
2 派生的数据类型
• 指针(pointer)
• 数组(array)
• 关联数组
• function
• delegate
3 自定义数据类型
• alias
• typedef
• enum
• struct
• union
• class
4 基类型(Base Types)
枚举的 基类型 就是其所依据的类型:
enum E : T { ...} // T 就是 E 的 基类型
类型定义的 基类型 就是其所组成的类型:
typedef T U; // T 就是 U 的 基类型
5 指针转换
D 允许指针到非指针、非指针到指针的转换;但是,决不要对指向由垃圾回收程序所分配的
数据的指针进行此类操作。
6 隐式转换
隐匿转换用于在需要的时候自动完成类型转换。
类型定义(typedef)或枚举(enum),可以隐式地转换到它的基类型,但在其它环境就需要显示转换。 A literal can be implicitly converted to a typedef.
例如:
typedef int myint;
int i;
myint m;
i = m; // 正确
m = i; // 错误
m = cast(myint)i; // 正确
m = 3; // OK
enum Foo { E }
Foo f;
i = f; // 正确
f = i; // 错误
f = cast(Foo)i; // 正确
f = 0; // error
f = E; // OK
7 整数提升
整数提升可以转换下列类型:
源类型 目标类型
bool int
byte int
ubyte int
short int
ushort int
char int
wchar int
dchar uint
如果类型定义或枚举的基类型时是上面左列中的某种类型,那么也会转换到右列中相应类
型。
8 常见的算术转换
常见的算术转换会将二元运算符的操作数转换为通用的类型。这个操作数必须已经是算术类
型。下面的规则将会按顺序应用:
1. 如果操作数是实型,那么其它的操作数将被转换成实型。
2. 如果操作数是双精度数,那么其它的操作数将被转换成双精度数。
3. 如果操作数是浮点数,那么其它的操作数将被转换成浮点数。
4. 否则才对每个操作数进行整数提升,步骤如下:
1. 如果两个操作数类型相同,则无需再作转换。
2. 果两个操作数都是有符号或无符号的,较小的类型会被转换为较大的类型。
3. 如果有符号的类型比无符号的类型大,无符号的类型会被转换为有符号的类型。
4. 否则有符号的类型会被转换为无符号的类型。
如果有一到两个操作数类型在经上面的转换后变成了类型定义或枚举,则最终类型是:
1. 如果操作数是相同类型,则结果也就是该类型。
2. 如果其中一个操作数是类型定义或枚举,而另一个的类型是类型定义或枚举的基类
型,则结果就是基类型。
3. 如果两个操作数是不同的类型定义或枚举,但有相同的基类型,则结果就是基类型。
整型值不能隐式地转换成其它在整数提升后不能代表整数位模式的类型。例如:
ubyte u1 = cast(byte)-1; // 错误,-1 不能表示成 ubyte 类型
ushort u2 = cast(short)-1; // 错误,-1 不能表示成 ushort 类型
uint u3 = cast(int)-1; // 错误,-1 不能表示成 uint 类型
ulong u4 = cast(ulong)-1; // 正确,-1 可以表示成 ulong 类型
浮点类型不能隐式转换成整数类型。
浮点复数类型不能隐式转换成浮点非复数类型。
浮点虚数类型不能隐式转换成浮点、双精度或实型类型。浮点、双精度或实型类型不能隐式
转换成浮点虚数类型
9 bool
bool(布尔类型)是一种只有一个字节大小的类型,它仅能存放 true 或 false,即真或假。
只能接受布尔类型操作数的操作符有:
& | ^ &= |= ^= ! && || ?:.
一个布尔值可以隐式地转换成任何整数类型: false 变成 0,而 true 变成 1。
单独的数字 0 和 1 可以隐式地转换成相应的布尔值 false 和 true。
测试一个表达式的布尔值即意味着:在算术类型时,测试 0 或!=0;
而测试 null 或 !=null 则是表示浮点或引用运算。
10 委托
在 D 中没有成员指针(pointers-to-members),但它支持一个更为有用的概念,即委托
(delegates)。委托是一个由两部分数据组成的聚集:一个是对象引用,另一个是函数指针。
当调用函数时,对象引用就形成 this 指针。
委托的声明同函数指针的声明很相像,区别就是使用关键字 delegate 来替代 (*) ,并且随后紧跟着标志符:
int function(int) fp; // fp 是指向函数的指针
int delegate(int) dg; // dg 是函数的委托
C 风格的声明函数指针的语法也被支持:
int (*fp)(int); // fp 是指向函数的指针
委托的初始化同函数指针一样:
int func(int);
fp = &func; // fp 指向 func
class OB
{ int member(int);
}
OB o;
dg = &o.member; // dg 是对象 o 和成员函数 member 的委托
委托不能用静态成员函数或者非成员函数初始化。
委托同函数指针一样调用:
fp(3); // 调用 func(3)
dg(3); // 调用 o.member(3)
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
属 性 (Properties)
每种类型和表达式都有可以查询的属性(Properties):
表达式 值
int.sizeof 计算得 4
float.nan 计算得浮点数nan(不是一个数)值
(float).nan 计算得浮点数nan值
(3).sizeof 计算得 4(因为3是一个int类型)
2.sizeof 语法错误,因为“2.”是一个浮点数
int.init int的默认初始值
int.mangleof 生成串“i”
int.stringof 生成串“int”
(1+2).stringof 生成串“1 + 2”
1 所有类型的属性
属性 描述
.init 初始值
.sizeof 字节大小(等同于 C 中的sizeof(type))
.alignof 对齐大小
.mangleof 表示类型'mangled'代表的字符串
.stringof 表示访类型的源表示(source representation)的字符串
2 整数类型的属性
属性 描述
.init 初始值 (0)
.max 最大值
.min 最小值
3 浮点类型的属性
属性 描述
.init 初始值 (NaN)
.infinity 无穷大
.nan NaN 值(在两个操作数都为nan时,进行= = 或 ! = 比较都会返回 flase)
.dig 换算为十进制表示后的精度
.epsilon 最小递增值 1
.mant_dig 尾数的位数
.max_10_exp 以 10max_10_exp 形式可以表示的最大整数值
.max_exp 以 2max_exp-1 形式可以表示的最大整数值
.min_10_exp 以 10min_10_exp 形式可以表示成的标准值的最小整数值
.min_exp 以 2min_exp-1 形式可以表示成的标准值的最小整数值
.max 可表示的最大值(除了无穷)
.min 可表示的最小值(除了 0 )
.re 实数部分
.im 虚数部分
4 .init 属性
.init 产生一个常量表达式,其值为默认初始值。如果应用到某个类型,其值为该类型的默认初始值。如果应用到某个变量或域,其值为这个变量或域的默认初始值。
例如:
int a;
int b = 1;
typedef int t = 2;
t c;
t d = cast(t)3;
int.init // 为 0
a.init // 为 0
b.init // 为 1
t.init // 为 2
c.init // 为 2
d.init // 为 3
struct Foo
{
int a;
int b = 7;
}
Foo.a.init // 为 0
Foo.b.init // 为 7
5 .stringof 属性
.stringof 会生成一个常量串,此字符串是它有前缀的“源表示(source sentation)”。
如果被应用到某个类型,那么它就是那种类型的字符串。如果被应用到一个表达式,那么它就是那个表达式的“源表示(source representation)”。
语义分析并不会处理那个表达式。
例如:
struct Foo { }
enum Enum { RED }
typedef int myint;
void main()
{
writefln((1+2).stringof); // "1 + 2"
writefln(Foo.stringof); // "Foo"
writefln(test.Foo.stringof); // "test.Foo"
writefln(int.stringof); // "int"
writefln((int*[5][]).stringof); // "int*[5][]"
writefln(Enum.RED.stringof); // "Enum.RED"
writefln(test.myint.stringof); // "test.myint"
writefln((5).stringof); // "5"
}
6 类和结构的属性
属性是成员函数,但在语法上被看作是域。属性可以被读写。属性可以通过调用一个不带实
参的方法来读取;再通过调用一个带有实参的方法来进行写入,其中的实参就会成为该属性
的值。
简单的属性可以表示成:
struct Foo
{
int data() { return m_data; } // 读取属性
int data(int value) { return m_data = value; } // 写入属性
private:
int m_data;
}
使用方法:
int test()
{
Foo f;
f.data = 3; // 等同于 f.data(3);
return f.data + 3; // 等同于 return f.data() + 3;
}
如果没有读方法就意味着属性是只写的。如果没有写方法就意味着属性是只读的。可以有多
个写方法共存,用正常的重载规则来决定采用哪个函数。
在其他方面,这些方法同其他的方法都是相同的。它们可以是静态的、拥有不同的链接方
式、被重载、被取地址等等。
注意:目前属性不能作为运算符 op=、++ 或 -- 的左值。
。。。。。。。。。