Slice1 (Specification Language for Ice)是一种用于使对象接口与其实现
相分离的基础性抽象机制。 Slice 在客户与服务器之间建立合约,描述应用
所使用的各种类型及对象接口。这种描述与实现语言无关,所以编写客户
所用的语言是否与编写服务器所用的语言相同,这没有什么关系。
Slice 定义由编译器编译到特定的实现语言 。编译器把与语言无关的定
义翻译成针对特定语言的类型定义和API。开发者使用这些类型和API 来
提供应用功能,并与Ice 交互。用于各种实现语言的翻译算法称为语言映射
(language mappings)。Ice 目前定义了C++ 和Java 的语言映射。
因为Slice 描述的是接口和类型(不是实现),它是一种纯粹的描述性
语言;你无法用Slice 编写可执行语句。
Slice 定义关注的焦点是对象接口、这些接口所支持的操作,以及操作
可能引发的异常。此外, Slice 还提供了一些用于对象持久的特性(参见第
21 章)。这需要相当多的支持机制;特别地, Slice 的相当一部分关注的是
数据类型的定义。这是因为,只有在其类型用Slice 进行了定义之后,数据
才能在客户与服务器之间交换。你不能在客户与服务器之间交换任意的
C++ 数据,因为 这可能会摧毁Ice 的语言无关性。但是,你总能创建一种
Slice 类型定义,与你想要发送的C++ 数据相对应,然后你就可以传送这种
Slice 类型了。
在此我们将介绍Slice 的完整语法和语义。因为Slice 的许多语法和语义
都是以C++ 和Java 为基础的,我们将特别关注Slice 与C++ 或Java 不同的
部分,或是Slice 以某种方式限制了等价的C++ 或Java 特性的部分。与
C++ 和Java 特性相同的Slice 特性通常会用例子来说明。
文件命名
含有Slice 定义的文件必须以.ice 扩展名结尾,例如, Clock.ice
就是一个有效的文件名。编译器拒绝接受其他扩展名。
预处理
Slice 支持#ifndef、#define、#endif,以及#include 预处理指令。它
们的使用方式有严格的限制:
• 你只能把#ifndef、#define,以及#endif 指令用于创建双包括
(double-include)块
• #include 指令只能出现在Slice 源文件的开头,也就是说,它们必须出现
在其他所有Slice 定义的前面。此外,在使用#include 指令时,只允许
使用<> 语法来指定文件名,不能使用""。
关键字 :
以下标识符是Slice 关键字:
关键字的大小写必须按照给出的方式拼写。
bool enum implements module string
byte exception int nonmutating struct
class extends interface Object throws
const false local out true
dictionary float LocalObject sequence void
double idempotent long short
结构 :
Slice 支持含有一个或多个有名称的成员的结构,这些成员可以具有任
意类型,包括用户定义的复杂类型。例如:
struct TimeOfDay {
short hour; // 0 - 23
short minute; // 0 - 59
short second; // 0 - 59
};
与在 C++ 里一样,这个定义引入了一种叫作TimeOfDay 的新类型。结构
定义会形成名字空间,所以结构成员的名字只需在围绕它们的结构里是唯
一的。
在结构内部,只能出现数据成员定义,这些定义必须使用有名字的类
型。例如,你不可能在结构内定义结构:
这个规则大体上适用于Slice:类型定义不能嵌套(除了模块确实支持
嵌套——参见4.11 节)。其原因是,对于某些目标语言而言,嵌套的类型
定义可能会难以实现,而且,即使能够实现,也会极大地使作用域解析规
则复杂化。对于像Slice 这样的规范语言而言,嵌套的类型定义并无必要
——你总能以下面的方式编写上面的定义(这种方式在风格上也更加整
洁):
struct Point {
short x;
short y;
};
struct TwoPoints { // Legal (and cleaner!)
Point coord1;
Point coord2;
};
代理 :
代理就像是能代表对象的指针(个人认为)。代理的语义与C++ 类实例指针的语义非常像:
• 代理可以为null (参见第88 页)。
• 代理可以悬空(dangle)(指向的对象已经不存在)
• 代理充当的是远地对象的本地“大使”;如果你调
用代理上的某个操作,你的调用会转发给实际的对象实现。如果对象实现
是在另外的地址空间中,就会产生一个远地过程调用;如果对象实现是并
置在相同的地址空间中的, Ice 就会使用普通的本地函数调用,从代理那里
调用对象实现
代理不能访问数据成员。这是因为代理没有数据成员的概念,它们代表的是接口,通过代理只能访问它的操作。
Slice 有很多东西, 就写了一些能看懂,或者个人感觉常用的。
我们针对Hello World 来编写它的Slice 它就是要客户端给告诉服务端执行一个在服务端输出一句话。
所以这个Printer.ice 文件的编写非常简单
1 module Demo{
2 interface Printer{
3 void printString(string s);
4 };
5 };
6
编译 : slice2cpp Printer.ice
编译后生成Printer.h 和 Printer.cpp 两个文件。 这两个文件要被客户端以及服务端用到 内部封装了我们定义的Printer这个接口,对于c++来说,也就是一个有着 类似virtual void printString(string s) = 0 这样的一个纯虚函数的一个骨架类,用来服务器端我们来继承并搞一个servant 。 同样 ,对于客户端, 有一个PrinterPrx它是一个类似c++指针的东西,反正很像的,我们可以通过它,和ice帮助我们封装好的一些通讯的方法,以及它的一些别的方法来编写我们的逻辑代码,就像编写在客户端一样,很方便。