文件名
Slice编译器对文件名有严格的要求,只能使用.ice扩展名。
预处理
与C++一样,Slice语言支持#ifndef、#define、#endif,以及#include 预处理指令。但是需要注意,只能使用#ifndef、#define、#endif来防止文件重复包含,不能用作条件编译指令;对于#include指令,只能使用尖括号,不对使用双引号;#include指令只能出现在源文件的开头。
注释
Slice同时支持C语言里的注释风格和C++的注释风格。
关键字
Slice内置了一些关键字,定义标识符时不能使用与关键字相同的名字,大小写不一样也不行。同时Slice是大小写不敏感的,但是关键字书写只能使用给定的大小写方式,Slice内置的关键字有bool、enum、implements、modle、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语言的标识符只能以字母开头,标识符中只能存在数字和字母,C++中标识符中可以包含下画线,但Slice语言中不允许,因为有些语言不支持。Slice语言是对大小写不敏感的,但是Slice仍然要求大小写的拼写方式一致,同时不允许两个标识符只有大小写不一致的情况。这样就使得Slice能够对大小写敏感的语言和大小写不敏感的语言都能进行良好的映射。
其它语言中的关键字
同样,其它语言中的关键字只要不是Slice中的关键字,都可以用作Slice的标识符,但是Slice会在语言映射时加上前缀,这样会使代码难于读懂,一般不建议这样做。
转义标识符
对于Slice中的关键字,Slice允许再前面加上"\"通过转义让其变成标识符,但是一般也不建议这样做。
保留标识符
另外,以Ice开头,以Helper、Holder、prx、Ptr结尾的标识符在Slice中是不允许存在的。以Ice开头的标识符是Ice内置的标识符,而以Helper、Holder、prx、Ptr是Slice在Java和C++映射中会使用这些后缀,保留是为了防止冲突。
基本类型
与其它语言一样,Slice规定了一些基本的数据类型。
类型 | 范围 | 长度 |
---|---|---|
bool | false或true | 未规定 |
byte | -128~127 | ≥8位 |
short | -2^15~2^15-1 | ≥16位 |
int | -2^31~2^31-1 | ≥32位 |
long | -2^63~2^63-1 | ≥64位 |
float | 单精度浮点数 | ≥32位 |
double | 双精度浮点数 | ≥64位 |
string | 由Unicode组成的字符串,不包含0字符 | 可变长度 |
自定义类型
除了内置的基本类型外,Slice还允许用户使用enum、struct、sequence、dictionary定义复杂类型。
枚举
Slice使用enum关键字定义枚举类型,其语法规则于C++类似。
但与C++不同的是,在Slice中不允许显示指定枚举符的值。
例如:enum Fruit { Apple = 0, Pear = 7, Orange = 2 }; 是不被允许的。
与C++一样,枚举符会进入包含它的名字空间,所以不同类型的枚举符也是不允许相同的。
例如:enum Fruit { Apple, Pear, Orange }; enum ComputerBrands { Apple, IBM, Sun, HP };也是不补充允许的。
结构
Slice使用struct关键字定义结构,与C语言中的结构体类似。
序列
Slice使用sequence关键字定义序列,其结构与语法都与C++中的vector,list等差不多。实际上Slice在映射为C++语言时,默认将序列映射为vector。如sequence<int> NumList; 定义了一个整数的序列。同样,也可以使用序列来构造序列。
词典
Slice使用dictionary关键字定义词典,其结构与语法与C++中的map差不多。例如dictionary<long, Employee> EmployeeMap;定义了一个词典,搜索关键字类型为long类型。
常量定义
与C++一样,Slice可以使用const关键字定义常量,其语法与c++类似,但是Slice中只能使用true或false初始化布尔型常量。
与C++一样,相同的两个字符串会自动连起来。如"hello " "world",会连起来变成"hello world"。
接口
Slice使用interface关键字定义一个接口,定义接口的同时,可以定义操作接口的函数。接口中C++中的抽象类类似,实际上,在映射为C++语言时,接口是映射为抽象类,接口中的函数也将映射为纯虚函数。
Slice不支持任何形式的重载,接口中的各个函数只能使用标识符来区别,这一特性主要是基于多语言映射的考虑,因为有些语言不支持重载。
接口中的函数参数可以有输入参数和输出参数,输出参数使用out关键字标明,同时Slice规定,函数中各参数的定义必须是输入参数在前,输出参数在后。
Nonmutating函数
如果某个函数并不改变它所操作的对象的状态(如获取某个属性的值就不会改变所操作的对象的状态),则可称该函数为Nonmutating函数,可以使用nonmutating关键字表明一个函数为Nonmutating函数,对于Nonmutating函数,当Ice无法确定调用是否发送到服务器时,可以进行重试,只有重试还是不行时,才会报告给客户端。
Idempotent函数
如果一个函数多次调用和一次调用对它所操作的对象的状态的影响是相同时(如将函数将某个属性修改为某个值时,则多次调用我一次调用是一样的;如果函数是将某个属性加1,则多次调用和一次调用效果是不一样的),则可以称为Idempotent函数,可以使用idempotent关键字表明一个函数是Idempotent函数,与Nonmutating一样,当Ice无法确定调用是否送达服务器时,可以重试,只有当重试还是不成功时,才会报告给客户端。
对于没有使用nonmutating和idempotent标识的函数,当无法确定调用是否到达服务器时,Ice不会重试,会立即将错误报告给客户端,因为重试可能会造成服务器端的函数多次被调用。
接口继承
在Slice中,接口支持继承,接口继承使用extends关键字。
Slice对于接口继承有一些限制,派生的接口不能有与其基接口有相同名字的函数。同时Slice中的接口支持多重继承,多重继承时,多个基接口不能有相同名字的函数。在多生继承时,多个基接口继承自同一个接口是允许的。
Slice中,所有的接口都隐含的继承自Object,Slice中显示的指定继承自Object是非法的。
自引用接口
Slice中,接口可以引用自己,从而形成一个接口链。
如
interface Link {
nonmutating SomeType getValue();
nonmutating Link* next();
};
就定义了一个接口链,next函数用于返回接口链中下一个接口代理的地址。接口链中最后一个接口的next函数调用会返回一个空代理。
类
与接口一样,Slice同时也支持定义类。但与类不同的是,接口只能在服务器端实现,而类可以在客户端实现,也就是说,每一个客户端都可以有自己的实现版本。可以使用class关键字定义一个类。
与接口不一样的是,类可以有成员变量,也可以成员函数。类也是不支持任何形式的重载,同时,类中的变量和函数也不能有相同的名称。
类继承
与接口一样,类也是可以支持继承的,类继承使用extends关键字。但与接口不同的时,类只支持单继承,不支持多继承。
自引用类
与接口一样,类也支持自引用。
如:
class Link {
SomeType value;
Link next;
};
这里与C++中不一样,这里的next并不是包含一个对象,而是包含了一个指针。使用自引用类可以形成一个链表。
链表最后一个对象的next为一个空指针。
实现接口的类
在Slice中,类可以用来实现接口的行为,使用implements关键字表明类实现了某个接口。同一个类可以实现多个接口。
提前声明
在Slice中,类和接口都可以提前声明,提前声明对于相互依赖的情况是很有用的,只要被依赖的类或接口被声明过,就可以被引用,而不必在被引用前定义。
模块
任何系统在不断扩大的过程中,名字冲突都是不可避免的问题,当然ICE也不例外。在Slice里可以定义模块以避免名字冲突,不同模块之间可以有相同的名字。Slice的模块与C++语言的名字空间比较类似,而实际上,Slice在映射为C++语言时,正是将模块映射为名字空间。
Slice使用module关键字加一对花括号定义模块。Slice中,模块可以重新打开,也就是说,可以在不同的地方定义一个模块的不同部分。如果一个模块要使用其他模块中的内容,则可以将需要使用的模块重新打开以对要使用的部分内容进行提前声明。
Ice模块
ICE run time的所有与特定语言无关的API都是在Ice模块中定义的。
类型ID
Slice里每一个类型都有一个唯一的ID以用于识别。类型ID以全局作用域(::)开始,然后在后面附加包含该类型的各嵌套模块的名字,最后加上该类型的名字,各部分之间以(::)分隔。可以使用ice_isA来检测一个对象是否属于某一个类型或其祖先类型(祖先类型:一个类型的父类型和父类型的祖先类型都是它的祖先类型;对应的,一个类型的子类型以及子类型的子孙类型都是它的子孙类型)。