Ceylon語言介紹第一部分(翻譯)——Hibernate之父的又一力作
原文:http://in.relation.to/Bloggers/IntroductionToCeylonPart1
這是Ceylon語言系列文章的第一部分。要注意的是語言的特性可能在最終版發(fā)布之前發(fā)生改變。
Ceylon編譯器還沒有完成,所以你還不能使用Ceylon編寫代碼。不管怎樣,我愿意讓社區(qū)參與語言和SDK的開發(fā),所以這個(gè)系列文章是給對(duì)Ceylon感興趣的人一個(gè)提前預(yù)覽。
讓我們從頭開始吧。
這個(gè)方法在控制臺(tái)打印出“Hello, World!”。這是一個(gè)頂層方法就像C語言函數(shù)--它直屬于包含它的包中,它不是一個(gè)任何類型的成員。你不需要接收一個(gè)對(duì)象來調(diào)用頂層方法,你只要像下面這樣就可以調(diào)用它:
Ceylon沒有Java風(fēng)格的靜態(tài)方法,但是你可以使用頂層方法來充當(dāng)同樣的角色。靜態(tài)方法存在的問題是它打亂了程序的塊結(jié)構(gòu)。Ceylon擁有嚴(yán)格的塊結(jié)構(gòu)--一個(gè)內(nèi)嵌的塊總是可以在所有包含它的塊中被訪問。這與Java的靜態(tài)方法不同。
這個(gè)方法使用了void關(guān)鍵字,這表示方法沒有返回值。當(dāng)方法被執(zhí)行時(shí),它調(diào)用另一個(gè)頂層方法writeLine(),這個(gè)方法在控制臺(tái)中顯示它的參數(shù)。
連同void關(guān)鍵字,還有一個(gè)命名為Void的類型,其再任何void方法中被返回,這也是Ceylon類型系統(tǒng)的根類型。
可能對(duì)void方法有一個(gè)返回類型很不解。對(duì)此的解釋就是Ceylon內(nèi)所有的方法都是函數(shù)。(但未必都是函數(shù)--比如hello(),一個(gè)Ceylon函數(shù)能夠有邊緣效應(yīng)。)
在一個(gè)非常抽象層里,每個(gè)方法都接受參數(shù)并有返回結(jié)果。對(duì)于Void類型,簡(jiǎn)單來說就是提供表示未知值和未知類型的一種途徑。你可以給Void分配任何值,包括null,但是它無法被再次回收,即使知道它的類型值是什么。因此理論上void方法有返回值,只是我們無法知道關(guān)于它值的任何信息。現(xiàn)在這聽起來可能沒什么用處,但是當(dāng)我們討論first-class函數(shù)和Ceylon類型安全的元數(shù)據(jù)模型時(shí)將證明其非常有用。
或者像這樣:
但是更好的方式是使用doc注解來寫注釋。
doc注解包含的文檔被包含在Ceylon文檔編譯器輸出中。文檔編譯器還將支持其它幾個(gè)注解,包括by,用來指定程序作者;see,用來關(guān)聯(lián)其它代碼元素;以及throws,報(bào)告用戶程序執(zhí)行拋出的異常類型。
同樣還有一個(gè)deprecated注解,用來說明程序元素在將來的版本中會(huì)被移除。
注意,當(dāng)一個(gè)注解的參數(shù)是字面原文形式,那么久不需要有關(guān)閉括號(hào)。
像doc,by,see和deprecated這類的注解不是一個(gè)關(guān)鍵字。它們只是普通的標(biāo)識(shí)符。同樣的對(duì)于語言中定義的注解:abstract,variable,shared,formal,actual和friends也都不是關(guān)鍵字。但void是關(guān)鍵字。
讓我們來詢問我們的程序,以便它告訴我們更多關(guān)于它自己的信息。
我們能看到Ceylon的字符串提供的兩個(gè)好處。第一就是可以分割字符串為多行,這對(duì)于在doc注解中寫文檔非常有幫助。第二個(gè)就是我們可以在字符串內(nèi)部插入表達(dá)式,從技術(shù)上來講,一個(gè)帶有表達(dá)式的字符串不在是一個(gè)真正的字符串了,而被看做一個(gè)字符串模板。
一個(gè)字符串表達(dá)式必須開頭和結(jié)尾都必須是字符串,下面的語法是錯(cuò)誤的:
在最后加上一個(gè)空的字符串就能修正上面例子的錯(cuò)誤。
注意,在Ceylon中這不是唯一連接字符串的方法。其實(shí)這只是對(duì)于在不變的字符串中插入變量或表達(dá)式有用。+操作符可作為另外一種選擇,還有更多靈活的例子:
但是不要看到這兩種方式的輸出是一樣的就認(rèn)為它們是等價(jià)的。+操作符僅僅是對(duì)表達(dá)式求值并產(chǎn)生一個(gè)不可變的String對(duì)象。而String模板是一個(gè)Gettable<String>的表達(dá)式,其不馬上對(duì)內(nèi)插表達(dá)式求值(有點(diǎn)像Hibernate里的懶加載)。如果你打印String模板對(duì)象兩次,你可能會(huì)看到兩個(gè)不同的輸出。其實(shí),String模板是一種closure(閉包)--一個(gè)重要的概念,我將在后面介紹。
對(duì)此,提供一個(gè)改良版本的Hello World程序,其從命令行接收一個(gè)名字作為輸入。我們必須考慮在命令行什么都沒輸入的情況,這樣就能給我們一個(gè)機(jī)會(huì)去體驗(yàn)Ceylon如何處理Null值,這可與Java于C#的處理方式有著很大的不同。
process對(duì)象有一個(gè)arguments屬性,它持有命令行參數(shù)的Sequence(順序)。本地變量name被這些參數(shù)初始化,參數(shù)如果存在的話,本地變量被聲明為String類型,否則他可能包含一個(gè)null值。if(exists...)控制結(jié)構(gòu)用來初始化本地非空變量greeting,如果name不是null的話就內(nèi)插到消息字符串中。最終,消息被輸出到控制臺(tái)。
這與Java不一樣,本地變量,參數(shù)和屬性都可以包含null值,但必須明確聲明其類型。這與其它語言持有類型安全的null值不同,在Ceylon中可選的類型不是一個(gè)封裝定值的algebraic數(shù)據(jù)類型,而是一個(gè)ad-hoc union type(聯(lián)合類型)。語法T|S表示聯(lián)合T和S。一個(gè)可選的類型Noting|X代表任何類型,X是一個(gè)定值類型。Ceylon允許我們使用縮寫X?代表Noting|X。
null值關(guān)聯(lián)一個(gè)Nothing類型的實(shí)例,但是它不是一個(gè)Object的實(shí)例。因此這是一種簡(jiǎn)單分配本地變量為Null(不是一個(gè)可選類型)的方式。
Ceylon編譯器也不允許你最T類型的值做任何“危險(xiǎn)”的事情,在Java里這樣會(huì)拋出NullPointerException。if(exists...)結(jié)構(gòu)讓我們從X?類型提取X類型的值,從而允許我們調(diào)用X值的方法。
事實(shí)上,沒有可能在一個(gè)可選類型的表達(dá)式里使用==操作符,你不能像在Java中那樣使用if(x==null)。這有助于避免像Java中的不良操作==,x==y在Java中如果x和y都是null將返回true.
在if(exists...)條件中可以聲明本地變量name:
自從我們不能再if(exists...)結(jié)構(gòu)外部使用變量name,這個(gè)語法在很多時(shí)候被首選使用。
這樣我們就不需要在調(diào)用方法時(shí)指定參數(shù)值。
默認(rèn)參數(shù)必須在所有必須參數(shù)列表的最后面。
Ceylon同樣支持參數(shù)序列,使用T...語法。我們將在for循環(huán)序列中講述。
這是Ceylon語言系列文章的第一部分。要注意的是語言的特性可能在最終版發(fā)布之前發(fā)生改變。
關(guān)于Ceylon
Ceylon是一門新的語言,它運(yùn)行在Java虛擬機(jī)上,目前正有我所在的小組開發(fā),它隸屬于RedHat。我們都是Java和Java生態(tài)系統(tǒng)的粉絲,因?yàn)樗膶?shí)用性、廣闊的文化氛圍和開發(fā)社區(qū)、天生適用于商業(yè)應(yīng)用以及可移植性。然而我們必須承認(rèn)這門語言和其現(xiàn)有的類庫,已經(jīng)過了15年的發(fā)展,它不能再提供更好的功能來解決現(xiàn)在的商業(yè)問題。- Ceylon的設(shè)計(jì)目標(biāo)包括:
- Java和C#開發(fā)者可以很容易的學(xué)習(xí)和掌握。
- 消除了一下Java的啰嗦語法,使其容易閱讀。
- 更加類型安全。
- 提供一個(gè)聲明式的語法來表達(dá)層級(jí)信息,比如定義用戶接口、結(jié)構(gòu)化數(shù)據(jù)以及系統(tǒng)配置,這導(dǎo)致了Java平臺(tái)過度的依賴于XML。
- 支持不變對(duì)象和高級(jí)函數(shù)(功能)
- 極好的元數(shù)據(jù)編程支持,這使得編寫框架變得非常容易
- 提供內(nèi)置模塊解決方案
Ceylon編譯器還沒有完成,所以你還不能使用Ceylon編寫代碼。不管怎樣,我愿意讓社區(qū)參與語言和SDK的開發(fā),所以這個(gè)系列文章是給對(duì)Ceylon感興趣的人一個(gè)提前預(yù)覽。
讓我們從頭開始吧。
編寫一個(gè)簡(jiǎn)單的程序
這是一個(gè)經(jīng)典的例子程序。void hello() {
writeLine("Hello, World!");
}
writeLine("Hello, World!");
}
這個(gè)方法在控制臺(tái)打印出“Hello, World!”。這是一個(gè)頂層方法就像C語言函數(shù)--它直屬于包含它的包中,它不是一個(gè)任何類型的成員。你不需要接收一個(gè)對(duì)象來調(diào)用頂層方法,你只要像下面這樣就可以調(diào)用它:
hello();
Ceylon沒有Java風(fēng)格的靜態(tài)方法,但是你可以使用頂層方法來充當(dāng)同樣的角色。靜態(tài)方法存在的問題是它打亂了程序的塊結(jié)構(gòu)。Ceylon擁有嚴(yán)格的塊結(jié)構(gòu)--一個(gè)內(nèi)嵌的塊總是可以在所有包含它的塊中被訪問。這與Java的靜態(tài)方法不同。
這個(gè)方法使用了void關(guān)鍵字,這表示方法沒有返回值。當(dāng)方法被執(zhí)行時(shí),它調(diào)用另一個(gè)頂層方法writeLine(),這個(gè)方法在控制臺(tái)中顯示它的參數(shù)。
連同void關(guān)鍵字,還有一個(gè)命名為Void的類型,其再任何void方法中被返回,這也是Ceylon類型系統(tǒng)的根類型。
doc "The root type, supertype of
both Object (definite values)
and Nothing (the null value)."
see (Nothing, Object)
shared abstract class Void() {}
both Object (definite values)
and Nothing (the null value)."
see (Nothing, Object)
shared abstract class Void() {}
可能對(duì)void方法有一個(gè)返回類型很不解。對(duì)此的解釋就是Ceylon內(nèi)所有的方法都是函數(shù)。(但未必都是函數(shù)--比如hello(),一個(gè)Ceylon函數(shù)能夠有邊緣效應(yīng)。)
在一個(gè)非常抽象層里,每個(gè)方法都接受參數(shù)并有返回結(jié)果。對(duì)于Void類型,簡(jiǎn)單來說就是提供表示未知值和未知類型的一種途徑。你可以給Void分配任何值,包括null,但是它無法被再次回收,即使知道它的類型值是什么。因此理論上void方法有返回值,只是我們無法知道關(guān)于它值的任何信息。現(xiàn)在這聽起來可能沒什么用處,但是當(dāng)我們討論first-class函數(shù)和Ceylon類型安全的元數(shù)據(jù)模型時(shí)將證明其非常有用。
添加內(nèi)嵌的文檔
通常給像hello()這樣重要的方法上添加注釋文檔是一個(gè)好習(xí)慣。一個(gè)方式就是使用C語言風(fēng)格的注釋,就像下面這樣:/* The classic Hello World program */
void hello() {
writeLine("Hello, World!");
}
void hello() {
writeLine("Hello, World!");
}
或者像這樣:
//The classic Hello World program
void hello() {
writeLine("Hello, World!");
}
void hello() {
writeLine("Hello, World!");
}
但是更好的方式是使用doc注解來寫注釋。
doc "The classic Hello World program"
void hello() {
writeLine("Hello, World!");
}
void hello() {
writeLine("Hello, World!");
}
doc注解包含的文檔被包含在Ceylon文檔編譯器輸出中。文檔編譯器還將支持其它幾個(gè)注解,包括by,用來指定程序作者;see,用來關(guān)聯(lián)其它代碼元素;以及throws,報(bào)告用戶程序執(zhí)行拋出的異常類型。
doc "The classic Hello World program"
by "Gavin"
see (goodbye)
throws (IOException)
void hello() {
writeLine("Hello, World!");
}
by "Gavin"
see (goodbye)
throws (IOException)
void hello() {
writeLine("Hello, World!");
}
同樣還有一個(gè)deprecated注解,用來說明程序元素在將來的版本中會(huì)被移除。
注意,當(dāng)一個(gè)注解的參數(shù)是字面原文形式,那么久不需要有關(guān)閉括號(hào)。
像doc,by,see和deprecated這類的注解不是一個(gè)關(guān)鍵字。它們只是普通的標(biāo)識(shí)符。同樣的對(duì)于語言中定義的注解:abstract,variable,shared,formal,actual和friends也都不是關(guān)鍵字。但void是關(guān)鍵字。
字符串和字符串內(nèi)插
Hello World程序--現(xiàn)在廣泛流行--提供非常有限的用戶體驗(yàn)。一個(gè)更典型的例子在不同的運(yùn)行時(shí)產(chǎn)生不同的輸出。讓我們來詢問我們的程序,以便它告訴我們更多關(guān)于它自己的信息。
doc "The Hello World program
version 1.1!"
void hello() {
writeLine("Hello, this is Ceylon " process.languageVersion
" running on Java " process.javaVersion "!");
}

void hello() {
writeLine("Hello, this is Ceylon " process.languageVersion
" running on Java " process.javaVersion "!");
}
我們能看到Ceylon的字符串提供的兩個(gè)好處。第一就是可以分割字符串為多行,這對(duì)于在doc注解中寫文檔非常有幫助。第二個(gè)就是我們可以在字符串內(nèi)部插入表達(dá)式,從技術(shù)上來講,一個(gè)帶有表達(dá)式的字符串不在是一個(gè)真正的字符串了,而被看做一個(gè)字符串模板。
一個(gè)字符串表達(dá)式必須開頭和結(jié)尾都必須是字符串,下面的語法是錯(cuò)誤的:
writeLine("Hello, this is Ceylon " process.languageVersion); //compile error!
在最后加上一個(gè)空的字符串就能修正上面例子的錯(cuò)誤。
writeLine("Hello, this is Ceylon " process.languageVersion "");
注意,在Ceylon中這不是唯一連接字符串的方法。其實(shí)這只是對(duì)于在不變的字符串中插入變量或表達(dá)式有用。+操作符可作為另外一種選擇,還有更多靈活的例子:
writeLine("Hello, this is Ceylon " + process.languageVersion +
" running on Java " + process.javaVersion + "!");
" running on Java " + process.javaVersion + "!");
但是不要看到這兩種方式的輸出是一樣的就認(rèn)為它們是等價(jià)的。+操作符僅僅是對(duì)表達(dá)式求值并產(chǎn)生一個(gè)不可變的String對(duì)象。而String模板是一個(gè)Gettable<String>的表達(dá)式,其不馬上對(duì)內(nèi)插表達(dá)式求值(有點(diǎn)像Hibernate里的懶加載)。如果你打印String模板對(duì)象兩次,你可能會(huì)看到兩個(gè)不同的輸出。其實(shí),String模板是一種closure(閉包)--一個(gè)重要的概念,我將在后面介紹。
處理沒找到的對(duì)象
大多數(shù)程序都要求接收輸入并產(chǎn)生輸出,并且程序依賴于接收的輸入。當(dāng)然,這么做對(duì)用戶來說有點(diǎn)苛刻,但是,一些額外的工作必須做!對(duì)此,提供一個(gè)改良版本的Hello World程序,其從命令行接收一個(gè)名字作為輸入。我們必須考慮在命令行什么都沒輸入的情況,這樣就能給我們一個(gè)機(jī)會(huì)去體驗(yàn)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);
}
void hello() {
String? name = process.arguments.first;
String greeting;
if (exists name) {
greeting = "Hello, " name "!";
}
else {
greeting = "Hello, World!";
}
writeLine(greeting);
}
process對(duì)象有一個(gè)arguments屬性,它持有命令行參數(shù)的Sequence(順序)。本地變量name被這些參數(shù)初始化,參數(shù)如果存在的話,本地變量被聲明為String類型,否則他可能包含一個(gè)null值。if(exists...)控制結(jié)構(gòu)用來初始化本地非空變量greeting,如果name不是null的話就內(nèi)插到消息字符串中。最終,消息被輸出到控制臺(tái)。
這與Java不一樣,本地變量,參數(shù)和屬性都可以包含null值,但必須明確聲明其類型。這與其它語言持有類型安全的null值不同,在Ceylon中可選的類型不是一個(gè)封裝定值的algebraic數(shù)據(jù)類型,而是一個(gè)ad-hoc union type(聯(lián)合類型)。語法T|S表示聯(lián)合T和S。一個(gè)可選的類型Noting|X代表任何類型,X是一個(gè)定值類型。Ceylon允許我們使用縮寫X?代表Noting|X。
doc "The type of null."
shared abstract class Nothing()
of nothing
extends Void() {}
shared abstract class Nothing()
of nothing
extends Void() {}
null值關(guān)聯(lián)一個(gè)Nothing類型的實(shí)例,但是它不是一個(gè)Object的實(shí)例。因此這是一種簡(jiǎn)單分配本地變量為Null(不是一個(gè)可選類型)的方式。
doc "Represents a null reference."
object nothing extends Nothing() {}
doc "Hides the concrete type of nothing."
shared Nothing null = nothing;
object nothing extends Nothing() {}
doc "Hides the concrete type of nothing."
shared Nothing null = nothing;
Ceylon編譯器也不允許你最T類型的值做任何“危險(xiǎn)”的事情,在Java里這樣會(huì)拋出NullPointerException。if(exists...)結(jié)構(gòu)讓我們從X?類型提取X類型的值,從而允許我們調(diào)用X值的方法。
事實(shí)上,沒有可能在一個(gè)可選類型的表達(dá)式里使用==操作符,你不能像在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 String name = process.arguments.first) {
greeting = "Hello, " name "!";
}
else {
greeting = "Hello, World!";
}
writeLine(greeting);
自從我們不能再if(exists...)結(jié)構(gòu)外部使用變量name,這個(gè)語法在很多時(shí)候被首選使用。
默認(rèn)參數(shù)
一個(gè)方法參數(shù)可以指定一個(gè)默認(rèn)值。void hello(String name="World") {
writeLine("Hello, " name "!");
}
writeLine("Hello, " name "!");
}
這樣我們就不需要在調(diào)用方法時(shí)指定參數(shù)值。
hello(); //Hello, World!
hello("JBoss"); //Hello, JBoss!
hello("JBoss"); //Hello, JBoss!
默認(rèn)參數(shù)必須在所有必須參數(shù)列表的最后面。
Ceylon同樣支持參數(shù)序列,使用T...語法。我們將在for循環(huán)序列中講述。
還有更多。。。
在第二部分,我們將看到如何定義一個(gè)自身類型:classes,interfaces和objects.posted on 2011-05-24 07:25 kuuyee 閱讀(2893) 評(píng)論(1) 編輯 收藏 所屬分類: JEE 、Ruby/Python/Ceylon