Ceylon语言介绍第一部分——Hibernate之父的又一力作

这是Ceylon语言系列文章的第一部分。要注意的是语言的特性可能在最终版发布之前发生改变。

关于Ceylon

Ceylon 是一门新的语言,它运行在Java虚拟机上,目前正有我所在的小组开发,它隶属于RedHat。我们都是Java和Java生态系统的粉丝,因为它的实用 性、广阔的文化氛围和开发社区、天生适用于商业应用以及可移植性。然而我们必须承认这门语言和其现有的类库,已经过了15年的发展,它不能再提供更好的功 能来解决现在的商业问题。

  • Ceylon的设计目标包括:
  • Java和C#开发者可以很容易的学习和掌握。
  • 消除了一下Java的啰嗦语法,使其容易阅读。
  • 更加类型安全。
  • 提供一个声明式的语法来表达层级信息,比如定义用户接口、结构化数据以及系统配置,这导致了Java平台过度的依赖于XML。
  • 支持不变对象和高级函数(功能)
  • 极好的元数据编程支持,这使得编写框架变得非常容易
  • 提供内置模块解决方案

最重要的是,Ceylon的设计目的是让大型团队更好的协作
Ceylon编译器还没有完成,所以你还不能使用Ceylon编写代码。不管怎样,我愿意让社区参与语言和SDK的开发,所以这个系列文章是给对Ceylon感兴趣的人一个提前预览。
让我们从头开始吧。

编写一个简单的程序

这是一个经典的例子程序。

void  hello() { 
    writeLine(
" Hello, World! " );
}


这个方法在控制台打印出“Hello, World!”。这是一个顶层方法就像C语言函数--它直属于包含它的包中,它不是一个任何类型的成员。你不需要接收一个对象来调用顶层方法,你只要像下面这样就可以调用它:

hello();


Ceylon没有Java风格的静态方法,但是你可以使用顶层方法来充当同样的角色。静态方法存在的问题是它打乱了程序的块结构。Ceylon拥有严格的块结构--一个内嵌的块总是可以在所有包含它的块中被访问。这与Java的静态方法不同。
这个方法使用了void关键字,这表示方法没有返回值。当方法被执行时,它调用另一个顶层方法writeLine(),这个方法在控制台中显示它的参数。

连同void关键字,还有一个命名为Void的类型,其再任何void方法中被返回,这也是Ceylon类型系统的根类型。

doc  " The root type, supertype of
      both Object (definite values) 
      and Nothing (the 
null  value). "
see (Nothing, Object)
shared 
abstract   class  Void() {}


可能对void方法有一个返回类型很不解。对此的解释就是Ceylon内所有的方法都是函数。(但未必都是函数--比如hello(),一个Ceylon函数能够有边缘效应。)

在 一个非常抽象层里,每个方法都接受参数并有返回结果。对于Void类型,简单来说就是提供表示未知值和未知类型的一种途径。你可以给Void分配任何值, 包括null,但是它无法被再次回收,即使知道它的类型值是什么。因此理论上void方法有返回值,只是我们无法知道关于它值的任何信息。现在这听起来可 能没什么用处,但是当我们讨论first-class函数和Ceylon类型安全的元数据模型时将证明其非常有用。

添加内嵌的文档

通常给像hello()这样重要的方法上添加注释文档是一个好习惯。一个方式就是使用C语言风格的注释,就像下面这样:

/*  The classic Hello World program  */  
void  hello() {
    writeLine(
" Hello, World! " );
}


或者像这样:

// The classic Hello World program 
void  hello() {
    writeLine(
" Hello, World! " );
}


但是更好的方式是使用doc注解来写注释。

doc  " The classic Hello World program "  
void  hello() {
    writeLine(
" Hello, World! " );
}


doc注解包含的文档被包含在Ceylon文档编译器输出中。文档编译器还将支持其它几个注解,包括by,用来指定程序作者;see,用来关联其它代码元素;以及throws,报告用户程序执行抛出的异常类型。

doc  " The classic Hello World program "  
by 
" Gavin "  
see (goodbye) 
throws  (IOException)
void  hello() { 
    writeLine(
" Hello, World! " );
}


同样还有一个deprecated注解,用来说明程序元素在将来的版本中会被移除。
注意,当一个注解的参数是字面原文形式,那么久不需要有关闭括号。
像doc,by,see和deprecated这类的注解不是一个关键字。它们只是普通的标识符。同样的对于语言中定义的注解:abstract,variable,shared,formal,actual和friends也都不是关键字。但void是关键字。

字符串和字符串内插

Hello World程序--现在广泛流行--提供非常有限的用户体验。一个更典型的例子在不同的运行时产生不同的输出。

让我们来询问我们的程序,以便它告诉我们更多关于它自己的信息。

doc  " The Hello World program 
       version  1.1 ! "
void  hello() { 
    writeLine(
" Hello, this is Ceylon  "  process.languageVersion
              
"  running on Java  "  process.javaVersion  " ! " );
}


我们能看到Ceylon的字符串提供的两个好处。第一就是可以分割字符串为多行,这对于在doc注解中写文档非常有帮助。第二个就是我们可以在字符串内部插入表达式,从技术上来讲,一个带有表达式的字符串不在是一个真正的字符串了,而被看做一个字符串模板。
一个字符串表达式必须开头和结尾都必须是字符串,下面的语法是错误的:

writeLine( " Hello, this is Ceylon  "  process.languageVersion);  // compile error!


在最后加上一个空的字符串就能修正上面例子的错误。

writeLine( " Hello, this is Ceylon  "  process.languageVersion  "" );


注意,在Ceylon中这不是唯一连接字符串的方法。其实这只是对于在不变的字符串中插入变量或表达式有用。+操作符可作为另外一种选择,还有更多灵活的例子:

writeLine( " Hello, this is Ceylon  "   +  process.languageVersion  +  
          
"  running on Java  "   +  process.javaVersion  +   " ! " );


但 是不要看到这两种方式的输出是一样的就认为它们是等价的。+操作符仅仅是对表达式求值并产生一个不可变的String对象。而String模板是一个 Gettable<String>的表达式,其不马上对内插表达式求值(有点像Hibernate里的懒加载)。如果你打印String模板 对象两次,你可能会看到两个不同的输出。其实,String模板是一种closure(闭包)--一个重要的概念,我将在后面介绍。

处理没找到的对象

大多数程序都要求接收输入并产生输出,并且程序依赖于接收的输入。当然,这么做对用户来说有点苛刻,但是,一些额外的工作必须做!

对此,提供一个改良版本的Hello World程序,其从命令行接收一个名字作为输入。我们必须考虑在命令行什么都没输入的情况,这样就能给我们一个机会去体验Ceylon如何处理Null值,这可与Java于C#的处理方式有着很大的不同。

doc  " Print a personalized greeting "  
void  hello() {
    String
?  name  =  process.arguments.first; 
    String greeting; 
    
if  (exists name) {
        greeting 
=   " Hello,  "  name  " ! " ;
    }
    
else  {
        greeting 
=   " Hello, World! "
    }
    writeLine(greeting);
}


process 对象有一个arguments属性,它持有命令行参数的Sequence(顺序)。本地变量name被这些参数初始化,参数如果存在的话,本地变量被声明 为String类型,否则他可能包含一个null值。if(exists...)控制结构用来初始化本地非空变量greeting,如果name不是 null的话就内插到消息字符串中。最终,消息被输出到控制台。
这与Java不一样,本地变量,参数和属性都可以包含null值,但必须明确声明 其类型。这与其它语言持有类型安全的null值不同,在Ceylon中可选的类型不是一个封装定值的algebraic数据类型,而是一个ad-hoc union type(联合类型)。语法T|S表示联合T和S。一个可选的类型Noting|X代表任何类型,X是一个定值类型。Ceylon允许我们使用缩写X?代 表Noting|X。

doc  " The type of null. "
shared 
abstract   class  Nothing() 
        of nothing
        
extends  Void() {}


null值关联一个Nothing类型的实例,但是它不是一个Object的实例。因此这是一种简单分配本地变量为Null(不是一个可选类型)的方式。

doc  " Represents a null reference. "   
object nothing 
extends  Nothing() {}

doc 
" Hides the concrete type of nothing. "   
shared Nothing 
null   =  nothing;


Ceylon编译器也不允许你最T类型的值做任何“危险”的事情,在Java里这样会抛出NullPointerException。if(exists...)结构让我们从X?类型提取X类型的值,从而允许我们调用X值的方法。

事实上,没有可能在一个可选类型的表达式里使用==操作符,你不能像在Java中那样使用if(x==null)。这有助于避免像Java中的不良操作==,x==y在Java中如果x和y都是null将返回true.

在if(exists...)条件中可以声明本地变量name:

String greeting; 
if  (exists String name  =  process.arguments.first) {
    greeting 
=   " Hello,  "  name  " ! " ;

else  {
    greeting 
=   " Hello, World! "
}
writeLine(greeting);


自从我们不能再if(exists...)结构外部使用变量name,这个语法在很多时候被首选使用。

默认参数

一个方法参数可以指定一个默认值。

void  hello(String name = " World " ) {
    writeLine(
" Hello,  "  name  " ! " );
}


这样我们就不需要在调用方法时指定参数值。

hello();  // Hello, World!
hello( " JBoss " );  // Hello, JBoss!


默认参数必须在所有必须参数列表的最后面。
Ceylon同样支持参数序列,使用T...语法。我们将在for循环序列中讲述。

你可能感兴趣的:(数据结构,编程,Hibernate,redhat,jboss)