原文见:http://blog.csdn.net/followshake/article/details/7366286
一、源文件规则
1、文件扩展名必须为.ice
2、在使用#include来包含其他的ice定义文件时,只能使用<>,不能使用""。在使用路径包含时,使用linux风格的斜线,不能使用windows风格的反斜线
3、每个slice定义文件中最好加上#ifndef的宏定义,防止文件的双重包含
4、文件必须是utf-8编码的
二、词法规则
1、slice文件支持c++的单行和多行注释
2、slice定义中的关键字均为小写
3、slice文件中关键字不能以下划线开始和结尾,当然这一规则也是可以打破的,在编译slice文件的时候使用“--underscore”的编译选项
4、slice的关键字虽然是大小写敏感的,但是为了保证ice能够映射到非大小写敏感的系统,因此最好不要采用不同的大小写拼写规则来区分两个关键字,即你可以认为是非大小写敏感的。
5、虽然说部分语言关键字不是slice的关键字,但是最好不要使用,因为slice的编译器会对这些语言相关的关键字进行特殊处理,从而带来代码可读性的降低
6、如果以前定义的slice文件中标示符与新的ice版本规则冲突,可以使用反斜线"\"来表示关键字为一个普通的标示符
7、slice定义文件中禁止标示符以“ice”开头。当然这一规则也是可以打破的,在编译slice文件的时候使用“--ice”的编译选项
8、slice定义文件中禁止标示符以"Helper"、“Holder”、“Prx”、“Ptr”结尾。
三、名字空间
1、在全局的名字空间中只允许出现名字空间的定义,即slice文件定义的最顶层必须是名字空间定义Moudle XXX
2、可以再不同的文件中使用相同的名字空间,就像多个c++文件中定义名字空间的不同类型一样
四、数据类型
1、slice提供的基本数据类型包括:bool、byte、short、int、long、float、double、string。扩展数据类型包括:enum、struct、sequence、dictionary。
2、特别注意slice不提供所谓的无符号类型,因为在某些程序设计语言中,就不提供native的unsigned类型,因此slice无法做无符号类型的语言映射
3、slice的string字符串必须使用unicode字符集,同时不能包含0的。如果需要使用包含其他字符集或者0的串,可以考虑使用byte结构来存储
4、布尔值bool的取值只能是flase或者true
5、byte类型在slice的语言映射中会始终保证是8字节的,同时在网络传输过程中也不会受网络和本地字节序的影响
6、slice的enum类型是不允许用户来制定枚举成员的取值的,但是slice能够确保枚举类型中后面的成员取值大于前面的成员取值,因此枚举成员是可以做大小比较的。slice不允许定义空的枚举类型,即枚举类型中必须有成员定义
7、slice中struct不支持类型的嵌套定义,即不允许在一个struct数据类型中再次定义一个struct的数据类型
8、结构中的基本数据类型和枚举类型支持在定义的时候指定默认值
9、需要使用变长的数据集合时,可以使用sequence来定义。sequence的一种特殊用法是用来标示可选值,因为sequence数据成员可以是空的数据集合。为了表示一个空的数据集合,我们一般这样来定义:sequence<XXX> TypeOpt; TypeOpt Parameter; Opt的后缀一般迎来标示该序列集合是允许为空的可选集合或者参数
10、需要使用类似map的类型映射结构时,可以使用dictionary来定义。但是dictionary的key字段是有约束的,只能是如下类型:byte、short、int、long、bool、string、enum、数据成员为整形或者字符串的结构。
11、slice常量定义允许的类型:整形、浮点、字符串、枚举。注意整型常量的取值不能带长度标示(l、L、u、U);浮点和字符串常量的语法定义基本同c++;常量取值时需要设置允许范围内的值,否则slice编译时会提示错误;常量定义取值时是可以引用其他常量的,只要确保其取值范围是合法的。
五、接口定义
1、接口操作必须包含如下信息:返回值、接口名称、输入参数类型和名称(如果存在)、输出参数类型和名称(如果存在)。
2、接口操作在参数排版上要求输出参数必须在输入参数的后面,并且不支持输入输出参数,即参数的数据传递方向是单一的。不支持默认值参数
3、同一个接口内部不允许操作重名的。即不支持接口操作的重载
4、如果某一个操作不会改变其接口对象的状态,请将其表示为nonmutating。即类似c++的常量函数(函数名后加const)。这样标示的好处是ice的运行环境能够在函数调用过程发生底层的一些错误情况下更积极的重新尝试,保证系统有更好的容错性能。
5、如果一个操作在一个接口对象上连续执行两次与一次的效果是一样的,那么为了能够让系统有更好的容错性能,请将接口表示为idempotent。从这个角度去理解,那么nonmutating操作也是idempotent的。
6、接口可以传递代理类型,即类似如c++的指针类型。这样做的一个好处是客户端能够传递一个带操作的数据结构给服务器端,这样客户端和服务器端能够传递除了数据之外的操作实现。需要做的事情仅仅是在slice中定义一个接口的指针,注意是“接口”。
7、接口是可以继承的,当然包含多重继承。但是需要注意的一点是,多重继承的多个基类中不能包含相同名称的操作。
8、始终的有一个观念就是,所有接口都共有同一个基类Object,但是你不能显示的从Object继承,这是slice隐私为大家实现的。注意Object的O大写了。这是关键字中的一个特例
六、异常处理
1、异常的定义有点类似结构,可以在其定义任何数据类型。但是和结构不同的是异常可以不包含任何数据成员
2、异常定义时也支持和常量一样的默认值定义语法规则。即基本数据类型支持在定义的时候制定默认值
3、可以设置某一个接口操作会抛出特定类型的异常,当然在该接口操作实现过程中也只能抛出申明的异常,否则ice的会报运行时错误
4、为了能够更好的保证系统的向下兼容性,最好在系统初始定义时就设置好操作的异常(即使初始实现时是没有异常抛出的)。
5、异常是支持继承的。即可以向下扩展异常的信息。但是不支持多重继承。可以再申明抛出基类异常的操作中抛出子类异常
6、服务器抛送给客户端的异常有如下几种情况:用户异常、ObjectNotExistException、FacetNotExistException、OperationNotExistException、UnknownUserException(操作的实现抛出了一个未声明的异常)、UnknownLocalException(系统未捕获操作申明的异常)、UnknownException(语言系统的异常)
七、类
1、类在数据成员定义上与结构相同、在操作定义上与接口类似。他是一个两中类型的混合物。类相比结构支持继承扩展、支持多态、支持自引用,相比接口有具备数据属性
2、为了能够具备更好的性能,如果struct就能够完成的事情,不要大费周章的来弄个class来搞
3、一定要区分类的自引用和接口的自引用的差异化。类的自引用时确实的值存在,但是接口的自引用时指针存在,即不是值域空间。因此在一些操作中,需要从时间和空间的角度来考虑是采用值引用还是指针引用。
4、在接口或者类的操作中如果参数是一个类,那么一定要注意,在客户端和服务器端的交互中仅仅传递了发送方的类成员,其操作的行为并没有进行传递,因此不能确保其操作的行为在客户端和服务器端的解释是一样的。为了能够在客户端和服务器端传递操作,最保险的做法是使用接口来代替类进行操作传递。当然如果你能保证客户端和服务器端的操作行为完全一致,用类来做不失为一种好的做法,因为在操作的执行上由于是在本地地址空间,而不会产生类似接口代理的RPC调用产生更重的调用开销。
5、类可是实现一个或多个接口,在这种场景下,一个类实例的接口调用,一定要区分该操作时从接口继承下来的,还是类扩展的。这样才知道其调用实现时远程的还是本地的。
6、类和接口一样,不能重载操作。在继承基类或者实现接口时,不能扩展和基类、实现接口相同的成员变量或者操作名称
7、一定要注意,如果使用类来代替接口传递代理(即指针)给接收方,那么仅仅是传递了一个代理,你只能理解是一个接口,而无法通过代理访问类的数据成员。
8、在相互引用的类和接口定义中,前置声明就成为了一种不得不用的手段。
八、其他
1、每个扩展的类和接口都有一个类型ID,一般而言,类型ID 起头是全局作用域(::),然后在后面附加包含该类型的各嵌套模块的名字,最后再以该类型自身的名字结束
2、Object类提供了一些一些基本的操作:ice_ping、ice_isA、ice_id、ice_ids
九、编译
1、slice2cpp [-h] [-v] [-DName] [-DName=Value] [-UName] [-IDir] [-E] [--output-dir Dir] [-d] [--ice] [--underscore] file
2、slice2html