ICE学习(六)-Slice语言介绍
Slice (Specification Language for Ice)语言建立了一种服务器和客户端之间的契约,他描述了接口和数据类型。这种描述和语言无关,因此,客户端和服务器不需要用同一种语言来编写。
读作 [slaɪs]
编译器可以将Slice定义编译转换为其他语言的数据类型和API。目前,支持C++, Java, C#, Python, Objective-C, Ruby, 和PHP。Slice只定义数据类型和接口,并不实现。关于数据类型,客户端和服务器必须使用SLICE中定义的数据类型。如果你的C++程序有一个数据要传送,你就要在Slice类型中找到对应的类型。
下面,我们会全面介绍Slice的语法和语义。
注释
支持C和C++式的注释
/*
* C style
*/
// C++ style</span>
关键字
关键字必须首字母小写,比如class和directionary。只有2个例外Object ,LocalObject必须首字母大写。
标识符
标识符必须以阿拉伯字母,后边可以接字母数字和下划线。
下划线不可以在开头和结尾,也不能有连续的下划线,比如_account, account_, get__account都是错误的。
大小写
不区分大小写,TimeOfDay 等同于TIMEOFDAY
关键字作为标识符
可以将其他语言中的关键字定义为标识符,比如switch是C++和JAVA的关键字,但你可以把他定义为标识符,这个标识符,会在C++中被自动的转换为_cpp_switch,在java中转为_switch。为了可读性,尽量避免使用到关键字。
保留标识符
所有Ice开头的标识符,都是保留的,用户不能使用。
注意,后缀为 Helper, Holder, Prx, Ptr的标识符同样是保留的,不要使用。
Modules对应C++,C#中的命名空间,JAVA中的PACKAGES。用于解决命名冲突的问题。名字中不要含有下划线
module ZeroC {
module Client {
// Definitions here...
};
module Server {
// Definitions here...
};
};
所有定义都必须在模块内。一个模块可以被定义在不同的位置,甚至在不同的源文件中。
module ZeroC {
// Definitions here...
};
// Possibly in a different source file:
module ZeroC { // OK, reopened module
// More definitions here...
};
注意,C++中不要把空指针传给STRING,可以用“”。
用户自定义类型有五种,这里只介绍最常用的两种。
- Enumerations
- Structures
- Sequences
- Dictionaries
- Constants and Literals
结构(Structures):
可以定义一个结构如下
struct TimeOfDay {
short hour; // 0 - 23
short minute; // 0 - 59
short second; // 0 - 59
};
也可以定义个包含其他结构的结构。
struct Point {
short x;
short y;
};
struct TwoPoints { // Legal (and cleaner!)
Point coord1;
Point coord2;
};
对于下列类型,可以在结构中赋予默认值
An integral type (byte, short, int, long)
A floating point type (float or double)
string
bool
Enum
如
struct Location {
string name;
Point pt;
bool display = true;
string source = "GPS";
};
序列(Sequences)
Sequences代表可变长的元素集合。如下
sequence<Fruit> FruitPlatter;
序列的元素也可以是序列。
struct TimeOfDay {
short hour; // 0 - 23
short minute; // 0 - 59
short second; // 0 - 59
};
interface Clock {
TimeOfDay getTime();
void setTime(TimeOfDay time);
};
上面代码定义了一个接口Clock,其中包含2个操作getTime ,setTime。
可以把接口定义视为C++中的类定义,或者JAVA中的接口定义,而操作就是成员函数。
一个操作的定义,和C++类似,基础的东西不累述了。注意不支持重载。一个接口中的操作,名字必须不同。
interface CircadianRhythm { void setSleepPeriod(TimeOfDay, TimeOfDay); // Error! // ...};
参数必须有名字,上面代码中没有名字是错误的。
一般来说,参数从客户端传到服务器。让服务器返回值,可以使用output关键字来使用output参数。如下。
interface CircadianRhythm {
void setSleepPeriod(TimeOfDay startTime, TimeOfDay stopTime);
void getSleepPeriod(out TimeOfDay startTime, out TimeOfDay stopTime);
// ...
};
注意,如果你的参数中有output参数,那么output参数必须放在后面。
一个参数不能同时是input和output(引用)
Option(n)代表可选参数,n必须是非负数,用来代表那个参数。
idempotent 用来标记那些执行多次,也不会影响结果的操作。比如setTime和getTime就是这样的操作。这个关键字允许ICE RUMTIME进行很大程度的优化。具体见http://doc.zeroc.com/display/Ice/Operations
客户端从服务器中取得一批数据。可以按下边代码来写。
Ice文件
module DataService { struct Data { long TIMESTAMP;//时间戳 double VALUE;//值 }; sequence<Data> ValueList; interface DataOut { long GetData(long lStartTime, long lEndTime,out ValueList datalist); }; };
客户端代码:
DataOutPrx cvt = DataOutPrxHelper.checkedCast( communicator.stringToProxy("converter:tcp -p 10004 -h 127.0.0.1")); OpcData[] data; long result = cvt.GetData(true, 10, 20, out data);
服务器代码:
public override long GetData(bool bHist, long lStartTime, long lEndTime,out Data[] datalist, Ice.Current current__) { Data a=new Data(); a.TIMESTAMP = 1; a.VALUE= 1; Data b = new Data(); ; b.TIMESTAMP = 2; b.VALUE= 2; Data c = new Data(); ; c.TIMESTAMP = 3; c.VALUE= 3; datalist=new Data[3]; datalist[0] = a; datalist[1] = b; datalist[2] = c; return 0; }