Slice语言语法介绍

  1. 一、介绍
    1、Slice定义关注的焦点是对象接口、这些接口所支持的操作,以及操作可能引发的异常。还提供了一些用于对象持久的特性。
    二、源文件
    文件命名
    2、含有Slice定义的文件必须以.ice扩展名结尾,编译器拒绝接受其它扩展名。对于大小写敏感的文件系统,扩展名必须小写。
    文件格式
    3、Slice是一种形式自由的语言,可以使用空格、横向和纵向制表符、换页,以及换行字符,Slice不会把语义与定义的布局关联起来。
    预处理
    4、Slice支持#ifndef、#define、#endif,以及#include预处理指令,使用方式有严格的限制:
    (1)、只能把#ifndef、#define,以及#endif指令用于创建双包括块。例如:
    #ifndef _CLOCK_ICE
    #define _CLOCK_ICE
    //#incluce directives here….
    // ……….
    #endif _CLOCK_ICE
    (2)、#include指令只能出现在Slice源文件的开头,也就是说必须出现在其它所有的Slice定义的前面,此外,在使用#include指令时,只允许使用< >语法来指定文件名,不能使用” ”。例如:
    #incluce <File.ice>
    (3)、通过#include指令,Slice定义可以使用其它源文件中定义的类型。Slice编译器会编译解析源文件中的所有代码,包括通过#include包括的文件。但是编译器只为在命令行上指定的顶层文件生成代码,你必须分别编译用#include包括的各个文件。
    定义次序
    Slice的成分,比如模块、接口、或类型定义,可以按照任何次出现,但标识符在使用之前必须先声明。
    三、语法规则
    1、注释
    在 Slice定义里,既可以使用C的、也可以使用C++的注释风格:
    /*
    *注释内容
    */
    //注释内容
    2、关键字
    Slice使用了一些关键字,必须以小写的方式拼写。例如:class和dictionary都是关键字,必须按照所示方式拼写。这个规则有两个例外:Object和LocalObject也是关键字,必须按照所示方式让首字母大写。
    3、标识符
    标识符以一个字母起头,后面可以跟任意数目的字母或数字。Slice标识符被限制在ASCII字符范围内,不能包含非英文字母。Slice标识符不能有下划线。
    (1)、大小写敏感
    标识符是大小写敏感的,但大小写的拼写方式必须保持一致。
    (2)、是关键字的标识符
    可以定义在一种或多种实现语言中的关键字的Slice标识符。例如:switch是合法的Slice标识符,但也是C++和Java的关键字。语言映射定义了一些规则来处理这样的标识符。要解决这个问题,通常要用一个前缀来使映射后的标识符不在是关键字。但是建议少使用其它语言的关键字作为Slice的标识符。
    (3)、转义的标识符
    在关键字的前面加上一个反斜杠,可以把Slice关键字用作标识符。但是建议少使用。
    (4)、保留的标识符
    Slice为Ice实现保留了标识符Ice及以Ice(任何大小写方式)起头的所有标识符。例如:Icecream,Slice编译器会发出错误警告。
    以下面任何一种后缀结尾的Slice标识符也是保留的:Helper、Holder、Prx,以及Ptr。Java和C++语言映射了使用了这些后缀,保留是为了防止冲突。
    四、基本的Slice类型
    Slice提供了一些内建的基本类型:
    bool、byte、short、int、long、float、double、string
    1、整数类型
    Slice提供了整数类型short、int、long,类型的范围分别是16位、32位、64位。注意,在有些架构上,这些类型有可能映射到更宽的原生类型。还有Slice没有提供无符号类型。
    2、浮点类型。
    3、串
    Slice串使用的是Unicode字符集。唯一一个不能出现在串中的字符是零字符。
    Slice数据模型没有null串的概念。
    4、布尔值
    布尔值只有false和true两种值。
    5、字节
    Slice的byte类型是一种(至少)8位的类型,当在地址空间之间传递时,它保证不会发生任何改变。这样允许交换二进制数据,在传送过程中这些数据不会被篡改。
    五、用户自定义的类型
    Slice允许定义复杂的类型:枚举(enumerations)、结构(structures)、序列(sequences)、词典(dictionaries)。
    1、枚举
    Slice的枚举类型定义看起来像是C++的枚举类型定义:
    Enum Fruit { Apple,Pear,Orange};
    这个定义引入了一种名为Fruit的类型,是一种拥有自己权利的新类型。关于怎样把顺序值赋给枚举符的问题,Slice没有作出定义。
    与C++不同,Slice不允许控制枚举符的顺序值。
    与C++里一样,Slice枚举符也会围绕它的名字空间,所以下面的定义是非法的:
    enum Fruit { Apple,Pear,Orang};
    enum ComputerBrands {Apple,IBM,Sun,HP};
    Slice不允许定义空的枚举。
    2、结构
    Slice支持含有一个或者多个有名称的成员的结构,这些成员可以具有任意类型,包括用户定义的复杂类型。例如:
    Struct TimeOfDay {
    short hour;
    short minute;
    short second;
    }
    在结构内部,只能出现数据成员定义,这些定义必须使用有名字的类型。
    3、序列
    序列是变长的元素向量:
    Sequence<Fruit> FruitPlatter;
    序列可以是空的,也就是说可以不包含元素;可以持有任意数量的元素,直到到达你的平台的内存限制。
    序列包含的元素自身也可以序列。
    4、词典
    词典是从键类型到值类型的映射。例如:
    struct Employee{
    long number;
    string firstName;
    string lastName;
    };
    Dictionary<long,Employee> EmployeeMap;
    词典的值类型可以是用户定义的任何类型。但词典的键类型只能是以下类型之一:
    整型(buyte、short、int、long、bool,以及枚举类型)
    string
    元素类型为整型或string的序列
    数据成员的类型只有整型或string的结构。
    5、常量定义与直接量
    Slice允许定义常量,类型必须是以下类型中的一种:
    整型、float、double、string
    例如:
    const bool app=true;
    const byte low=0X0f;
    const string ad=”aa”;
    const short th=42;
    const double PI=3.1416;

    enum Fruit { Apple,Pear,Orange};
    const Fruit fa=Pear;

    直接量的语法与C++ 和Java的一样(有一些小的两位):
    布尔常量只能用关键字false和true初始化(不能用0和1)。
    和C++一样,可以用十进制、八进制、十六进制方式来指定整数直接量。
    注意:用于指示长常量和无符号常量的后缀是非法的:
    const long w=0u;l
    const long wt =100000L;
    整数直接量的值必须落在其常量类型的范围内。
    浮点直接量使用的是C++的语法,除了不能用l或L后缀来表示扩展的浮点常量,但是f和F是合法的(但会被忽略)。值必须落在其常量类型(float或double)的范围内。
    串直接量支持与C++相同的转义序列。
    注意:Slice没哟null串的概念,因此,在Ice平平台的任何地方它都不能用作合法的串值。
    六、接口、操作、异常
    1、参数与返回值
    操作定义必须包含返回类型,以及0个或更多的参数定义。
    一个操作可以有一个或多个输入参数。参数名是必需的,不能缺省参数名。要把值从服务器传到客户,可以使用输出参数,这种参数用out关键字指示。
    如果操作既有出入参数,又有输出参数,输出参数必须放在输入参数的后面。
    Slice不支持既是输入、又是输出参数的参数(传引用调用)。
    2、Slice不支持任何形式的操作重载。
    同一个接口中的各个操作必须具有不同的名称,不管参数的类型是什么,数目是多少。之所以存在这个限制,是因为重载函数无法有效的映射到没有内建的重载支持的语言。
    3、Nonmutating操作
    Nonmutating关键字说明,操作不会改变它的对象的状态。这是有用的,原因有两个:
    (1)、语言映射可以利用关于操作行为的这项附件知识。例如:在使用C++时,nonmtating操作会映射到骨架类上的C++ const成员函数。
    (2)、知道了某个操作不会修改它的对象的状态,Ice run time就了可以尝试进行更积极的错误恢复,特别地,Ice会保证操作调用的“最多一次”语义。
    对于普通的操作, Ice run time 在处理错误时必须保守。例如,如果客户发送一个操作调用给服务器,然后连接断掉了,在这种情况下,客户端run time 无法知道它所发送的请求是否已实际到达服务器。这意味着,客户端run time 不能通过重新建立连接、并再次发送请求来进行错误恢复,因为这可能会造成操作两次调用,从而违反“最多一次”语义;客户端run time 别无选择,只能把错误报告给应用。
    而另一方面,对于nonmutating 操作,客户端run time 可以尝试重新建立与服务器的连接,并安全地再次发送先前失败的请求。如果第二次尝试能够联系上服务器,那么万事大吉,应用不会注意到发生过(暂时的)失败。只有在第二次尝试也失败的情况下,客户端run time才需要把错误报告给应用(可以通过Ice 的一个配置参数来增加重试次数)。
    (3)、Idempotent操作
    如果对某个操作进行两次连续的调用,其效果与一次调用是一样的,这个操作就是idempotent操作。
    操作的情况一样, Ice run time 利用这一知识来更积极地进行错误恢复。
    一个操作可以有nonmutating 修饰符,也可以有idempotent 修饰符,但不能同时有这两个修饰符(nonmutating 隐含了idempotent)。
    4、用户异常
    Slice允许定义用户异常,用以向客户指示错误的情况。
    exception Error { };

    exception RangeError {
    TimeOfDay errorTime;
    TimeOfDay minTime;
    TimeOfDay maxTime;
    };
    用户异常很像是含有一些数据成员的结构。但是,与结构不同,异常可以有零个数据成员,也就是说,是空的。当操作的实现出错时,异常允许你向客户返回任意数量的出错信息。操作可以使用异常规范来说明可能会有异常返回给客户:
    interface Clock {
    nonmutating TimeOfDay getTime();
    idempotent void setTime(TimeOfDay time)
    throws RangeError, Error;
    };
    操作只能抛出在它的异常规范中列出的那些用户异常。
    不能把异常当作参数值传递。
    不能把异常用作数据成员的类型。
    不能把异常用作序列的元素类型。
    不能把异常用作词典的键或值类型。
    不能抛出非异常类型的值(比如int 或string 类型的值)。
    5、异常继承
    异常支持继承,只支持单继承。
    注意,如果某个操作的异常规范指明了具体的异常类型,该操作的实现在运行时也可能会抛出派生层次最深的异常。
    6、Ice运行时异常
    操作的异常规范不能列出任何运行时异常。
    所有的Ice 运行时异常和用户异常都处在一个继承层次中。
    Ice运行时异常的继承结构:


    Ice 运行时异常的完整层次(服务器可能会发出有阴影的异常):


    6、接口语义与代理
    接口是有资格的类型,可以作为参数传递,*操作符叫作代码操作符。
    代理可以为null,代理可以悬空(指向的对象已经不存在),通过代理分派的操作使用的是迟后绑定:如果与代理的类型相比,代理所代表的对象的实际运行时类型派生层次更深,调用的就将是派生层次最深的接口的实现。
    注意,在共享语义方面,代理的行为也和指针非常像:如果两个客户都有一个代理,指向相同的对象,一个客户造成的状态变化就会被另一个客户看到。
    代理是强类型的。
    7、接口继承
    (1)、接口继承的局限
    如果一个接口使用多重继承,它不能从不止一个基接口那里继承相同的操作名称。
    (2)、隐含地继承Object
    所有Slice接口最终都派生自Object.
    (3)、Null代理
    (4)、自引用的接口
    代理具有指针语义,所以可以定义自引用的接口:
    interface Link {
    nonmutating SomeType getValue();
    nonmutating Link* next();
    };
    (5)、空接口
    Slice空接口是合法的。
    (6)、接口继承\实现继承
    Slice继承只是建立在类型兼容性,并没有说出任何与接口的实现方式有关的事情。
    七、类
    Slice还允许定义类。类像是接口,都有操作;类像是结构,都有数据成员。这样就产生了一种混合的对象,可以把它当作接口,通过引用进行传递,也可以把它当做值,通过值进行传递。类提供了很大的架构灵活性,类允许在客户端实现行为,而接口只允许在服务器端实现行为。
    类支持继承,因此是多态的:在运行时,只要实际的类类型是从操作的型构的形参类型派生的,就可以把一个类实例传给一个操作。这使得类能够用作类型安全的联合。
    1、 简单类
    Slice的类型定义与结构定义类型,但是用关键字class。例如:
    class TimeOfDay {
    short hour; // 0 - 23
    short minute; // 0 - 59
    short second; // 0 – 59 };
    能使用Slice结构的地方,都能使用Slice类,但是出于性能的上的考虑,结构已经够用,就不应该使用类。与结构不同,类可以使空。
    2、 类继承
    与结构不同,类支持继承。
    3、 类的继承语义
    类使用的传值语义和结构一样。如果把一个类实例传给一个操作,这个类和它的所有成员都会被传递。
    4、 类用作联合
    Slice没有提供专门的联合,可以从共同的基类派生多个类,从而得到与使用联合相同的效果。

posted on 2017-02-28 15:12  滴滴过  阅读(484)  评论(0)    收藏  举报

导航