除了Slice提供的基本类型以外,Slice还允许你自定义复合类型:枚举、结构、序列和词典。
枚举
Slice的枚举定义看起来就像C++的枚举定义一样:
enum Fruit { Apple, Pear, Orange };
上面的代码定义了一个名为Fruit的类型,Fruit是一种拥有自己权利的新的类型。Slice没有定义如何给枚举赋顺序值,但是Slice保证枚举的顺序值从左向右递增。
不同于C++,Slice不允许你控制枚举的顺序值,例如下面的代码是错误的:
enum Fruit { Apple = 0, Pear = 7, Orange = 2 };
实际上,只要你不在地址空间之间传递枚举的顺序值,那么你就不关心枚举的值是多少。例如,客户端向服务器发送了一个0值,用来表示Apple,这样就会引起问题,因为服务器可能不使用0值来表示Apple。但是,如果直接向服务器发送Apple,如果Apple在被接受的地址空间中使用一个不同的值表示,那么那个值会被Ice运行时正确的对应到Apple。
Slice不允许定义空的枚举。同时,Slice的枚举会进入封闭的命名空间,如下的代码是错误的:
enum Fruit { Apple, Pear, Orange };
enum ComputerBrands { Apple, IBM, Sun, HP };
上面的代码中Apple被二次定义了。
结构
Slice支持容纳一个或多个任意类型的有名称得成员的结构,包括了用户自定义的复合类型,例如:
short hour;
short minute;
short second;
}
上面的代码定义了名为TimeOfDay的新类型。结构定义形成了一个命名空间,因此结构中的成员的命名需要保持唯一性。
结构中不能出现结构定义,例如下面的代码是错误的:
{
struct Point
{
short x;
short y;
};
Point coord1;
Point coord2;
};
这条规则在Slice中的通用描述就是:除了模块,类型不能嵌套定义。这样做可以避免不同语言的不同的定义要求造成的冲突。所以,为了能够定义上面代码中的类型,你可以把两个结构分开定义。
序列
序列是不定长度的元素向量。如下:
sequence<Fruit> FruitPlatter;
一个序列是可以为空的,也就是说,序列可以不容纳元素,或者序列可以容纳在内存容量允许的范围之内的任意数量的元素,
序列的元素也可以是序列,就是说,你可以创建下面的序列:
sequence<FruitPlatter> FruitBanquet;
序列用来构造多种集合,例如向量、列表、队列、集合、包或者树。
一个特殊的序列的用法已经变成了惯用的方法,即使用序列来提供可选的值。例如,我们可能有一个Part结构来记录装配到汽车的零件的详细信息,这个结构可以记录如零件的名称,描述,重量,价格和其他的信息等。备用零件通常有一个序列号,我们是噢有那个long类型的值来表示。实际上,一些零件,例如螺丝,我们通常没有螺丝的序列号,所以我们在螺丝的序列号李存放什么内容呢?下面有一些处理的选择:
- 使用一个标记值(例如0)来指出没有序列号的情况。这个方法通常是可以正常工作的,只要所提供的标记值有效。似乎没有人会使用0来作为一个零件的序列号。但是,对于其他的一些值,例如温度,0就是一个不能作为标记值的值。
- 将序列号的类型从Long改为string。string有自己的标记值,即空串。所以我们可以使用一个空串来指出没有序列号的情况。这样也是有效的,但是却违背了一个原则:我们不应该为了得到一个标记值而改变事物表示自身的自然的方法。
- 增加一个标示位用来标示序列号是否有效,例如:
string name;
string description;
//
bool serialIsValid;
long serialNumber;
};
这样做可能会给我们带来另一个麻烦:迟早会有人因为忘了判断serialIsValid的值而直接使用serialNumber。
- 使用一个序列来建立可选的字段。例如:
struct Part{
string name;
string description;
//
SerialOpt serialNumber;
}
通常,Opt后缀表明这个一个可选的元素。如果序列是空的,那么很显然没有序号,如果序列有一个值,那么那个值就是序列号。很明显,这样做有一个缺点,那就是有人会故意放多个值到序列中。这个做法可以通过加入一个特殊通途的Slice结构来解决。实际上,可选值很少使用,没有必要加入一种特定的语言特征来解决。
字典
字典是键、值类型的映射。例如:
long number;
string firstName;
string lastName;
};
dictionary<long, Employee> EmployeeMap;
上面的定义创建了一个名为EmployeeMap的字典,它达到了从employee编号到一个包含有employee详细信息的结构的映射。
字典能够用来实现稀疏数组,或者任何使用非整数键值类型的用于查找的数据结构。尽管可以同uo设置一个包含了键值对的结构的序列也能用来构造类似的事情。但是字典更适合:
- 字典清楚地表达了设计者的意图,即提供了一个从值的域到值的范围的映射。
- 在编程语言级别上,序列被用向量的形式实现,也就说,序列不适合构建稀疏的域,而且,如果要定位一个元素需要线形的查找。换句话说,字典作为支持有效的查找的数据结构实现,其效率可以是:O(log n)甚至更好。
字典的键值不一定要是整形,它可以是下面的数据类型的任何一种:
- 整形(byte,short,int,long,bool以及枚举类型)
- string
- 使用整形或string作为元素的序列
- 只容纳有整形或string类型的成员的结构
常量定义和直接量
Slice允许你定义常量。常量定义必须是下面的类型中的一种:
- 整形(bool, byte, short, int, long或者枚举)
- float 或 double
- string
定义常量的语法与C plus plus和Java类似(有一点小的不同):
- 布尔类型只能用关键字false和true初始化
- 与C plus plus一样,整数类型可以用decimal,octal或二进制初始化。但是需要注意的是,如果你认为byte是数字而不是位模式,那么你可能在不同的实现语言中得到不同的结果。例如,在C plus plus中,byte映射到char,而对于不同的平台,char可能是有符号的或无符号的。注意,在C plus plus中使用的long和无符号常量的后缀(l,L,u,U)在Slice中是不合法的。
- 浮点直接量定义使用C plus plus的语法,但是你不能使用l或者L后缀来定义扩展的浮点常量。而f和F是合法的。
- String直接量定义支持 C plus plus的转义序列。与C plus plus相同,Slice把相邻的字符串直接量连接起来。