本文簡單介紹了Smalltalk語言的一些語法規(guī)則檬寂,Smalltalk語言中使用MVC模式來構(gòu)建用戶界面痒蓬,即MVC模式是起源于Smalltalk語言的瓶颠,不過Smalltalk的中文資料太少贸桶,這篇翻譯文章也是為我自己將要寫的續(xù)集文章——淺談MVC框架模式做一個鋪墊锰瘸。
閱讀Smalltalk程序
我對smalltalk語言的介紹是基于我處理其他語言的方法:
- 審查字符集和符號
- 審查保留字(關(guān)鍵字)
- 審查每個獨特的語法格式
- 審查每個獨特的語義形式
- 審查代碼庫 (雖然這一條要求只占了全部要求的20%,但它卻要求你付出80%的努力)
那么從這里開始吧蹬碧。
1.字符集和符號
標(biāo)準(zhǔn)字符集由十二個特殊字符組成:# : ^ . ' | " ; ( ) [ ]
符號有:{標(biāo)識符} {數(shù)字} {字符串} {注釋} {二進制操作符} {關(guān)鍵字} {特殊符號}
標(biāo)識符
跟你所想的一樣舱禽,除了使用大寫字母開頭,而不是下劃線恩沽。
capitalLettersLikeThis [??]
rather_than_underscores [?]
數(shù)字
這個也是跟你想的一樣
‘字符串’
使用單引號
”注釋“
使用雙引號
二進制操作符
由一個或兩個字符組成誊稚,組成二進制操作符的字符在實現(xiàn)之間有一點不同,不過如果只是為了實現(xiàn)閱讀Smalltalk程序這個目標(biāo)罗心,你可以假設(shè)任何不在上面的{特殊符號}里的非字母數(shù)字的字符可以組成{二進制操作符}.比如:
+
++
?*
->
關(guān)鍵字
僅僅是一個有冒號結(jié)尾的標(biāo)識符片吊,比如anyIdentifierLikeThis:
就是一個{關(guān)鍵字}。在Smalltalk里面协屡,一個關(guān)鍵字只有在它形成“關(guān)鍵字消息”的時候才有意義,它是一種區(qū)域性的符號(不同于標(biāo)識符或字符串),這意味著它作為一個單獨的符號并不特殊全谤。一些語言有像是BEGIN
和END
之類的{關(guān)鍵字}在語言內(nèi)有著特殊的意義,而關(guān)鍵字在Smalltalk中則不是這樣的,這是一種嚴(yán)格的語法格式房匆。
特殊符號
是一些特殊字符,作為分隔符來解析語言漫萄。
#
用于符號的開頭如:#symbol
:
用于關(guān)鍵字的結(jié)尾如:keyword:
^
用于問答對象如:^answerThisObject
.
分隔語句
'
限定一個字符串
|
表示臨時變量
"
注釋
;
級聯(lián)語句
(
表達式的開始
)
表達式的結(jié)束
[
閉包域的開始
]
閉包域的結(jié)束
2.保留字
有五個保留字:nil false true self super.
這些都是保留字,因為編譯器盈匾、優(yōu)化器和VM都知道它們腾务。
nil
這個值代表未初始化的值,它也代表了某個值可能忘了初始化削饵,就好像“我沒有主意”岩瘦,“從未有過任何值”之類的。nil有時候會被NullObject或是ExceptionalValues錯誤的使用窿撬。
true and false
分別屬于單例類True和False启昧。
self
當(dāng)你在閱讀或是使用這個詞時,表示你當(dāng)前使用的對象的引用劈伴。如果對象的類沒有這個方法密末,你要去最近的超類(父類)中讀取這個方法。
super
與self表示相同的引用對象跛璧。
閱讀下面這一段100次严里,直到你接受了這個事實才繼續(xù)往下看。
為什么兩個名字會指向相同的對象呢追城?這可能很難理解直到你使用它刹碾,super和self是指同一個對象,當(dāng)你試圖弄清楚對象將執(zhí)行哪個方法來響應(yīng)發(fā)送的消息時漓柑,假設(shè)對象的類沒有這樣的方法教硫。換句話說,如果對象的類確實有一個方法來傳遞你發(fā)送的消息辆布,始終會從對象的超類中開始查找這個方法瞬矩。這樣你就可以擴展超類的行為,而不必重寫它锋玲。比如景用,定義和超類一樣的方法aMethod,然后:
>>aMethod
super aMethod.
self doSomeMoreStuff.
或者定義aMethod來做一些新的事情惭蹂,然后跟著超類的方法伞插。
>>aMethod
self doSomeMoreStuff.
super aMethod.
3.語法格式
在Smalltalk中有一個很重要的,但你以前可能不太熟悉的概念:
任何事物都是對象
以及
所有代碼都采用單一的概念形式:anObject withSomeMessageSentToIt.(注:Smalltalk中的消息發(fā)送機制)
如果你想繼續(xù)使用C++盾碗、Java或其他面向?qū)ο蟮恼Z言工作媚污,那么你很可能不能理解這是什么。
如果它開始對你有意義廷雅,那你就停止閱讀Smalltalk耗美,因為你正處于危險之中京髓,稍后將詳細(xì)介紹這些...
這里有六個語法格式:
1. 一元消息發(fā)送
object isSentThisUnaryMessage.
2. 二元消息發(fā)送
object {isSentThisBinaryOperator} withThisObjectAsOperand.
3. 關(guān)鍵字消息發(fā)送
object isSentThisKeywordMessage: withThisObjectAsParameter.
object isSent: thisObject and: thisOtherObject.
object is: sent this: message with: 4 parameters: ok.
object is: sent this message: with parameters: (1 + 2).
object is: (sent this) message: (with) parameters: (3).
這可能有一些奇怪,直到你明白為止商架。關(guān)鍵字消息寫成C函數(shù)調(diào)用可能會看起來像這樣:
isSentThisKeywordMessage(object,andParameter);
isSentAnd(object,thisObject,thisOtherObject);
isThisWithParameters(object,sent,message,4,ok);
isMessageParameters(object,this(sent),with,(1+2));
isMessageParameters(object,(this(sent)),(with),(3));
關(guān)鍵字消息就像這樣:
isSentThisKeywordMessage:
isSent:and:
is:this:with:parameters:
is:message:parameters:
注意一個參數(shù)堰怨,或是一個二元消息的操作符,既可以是一個對象蛇摸,也可以是向一個對象發(fā)送的消息备图。就像在C里面一個參數(shù)可能是操作符,也可能是操作數(shù)赶袄;既可以是一個字面值{對象}揽涮,一個常量,一個變量弃鸦,一個指針表達式绞吁,或是一個函數(shù)調(diào)用。
4. 代碼塊(也叫閉包)
[thisObject willGetThisUnaryMessageSentToIt]
[:someObject| someObject willGetThisMessage]
[:first :second| thisObject gets: first and: second]
[:first :second| first gets: thisObject and: second]
一個塊可以被認(rèn)為是一個臨時類的唯一實例唬格,沒有超類,只有一個方法家破。{不是真的,但是這樣思考直到你真的明白}购岗。什么是一個方法汰聋?這取決于參數(shù)的數(shù)量:
如果一個閉包含有 | 這是唯一已知的方法 | |
---|---|---|
沒有參數(shù) | ["一個沒有參數(shù)的閉包"] | value |
一個參數(shù) | [:x| “有一個參數(shù)的閉包”] | value: actualParameter |
兩個參數(shù) | [:x :y|"有兩個參數(shù)的閉包"] | value:firstActual value:secondActual |
... |
示例:
[object messageSent] value.
當(dāng)這個必報接受一個一元消息,這個一元消息messageSent將被傳遞給對象object喊积。
[some code] value.
value消息將會是閉包執(zhí)行some code烹困。
[:one| any code can be in here] value: object.
value: object消息將會與第一個參數(shù)one綁定,然后執(zhí)行代碼乾吻。
5. 返回值
^ resultingObject
任何方法都會至少有一個返回值髓梅,即便你看不到它。一般情況下你都可以看到它绎签,在方法的最后一行枯饿,如果你沒有看到它,默認(rèn)將會返回^self
它的另一個作用是提前退出诡必,比如:
object isNil ifTrue: [^thisObject].
object getsThisMessage.
^self
這可能會讓你有些不習(xí)慣奢方,因為這不符合結(jié)構(gòu)化編程里面的“單一入口/單一出口”原則。注意Smalltalk的程序很短爸舒,不蟋字,是非常的短,我們根本不在乎扭勉。一個方法僅僅只有幾行程序會讓你頭腦清楚鹊奖,并且如果我們以后要對所有的出口點作出改變也比較容易。
6. 定義方法
使用瀏覽器時涂炎,實際上并沒有看到這種語法形式嫉入,但是當(dāng)Smalltalk在外部環(huán)境中被描述時焰盗,使用以下語法來表示方法的定義:
- 一元
ClassName>>methodSelector
someObject getsThisMessage. someOtherObject
getsThisOtherMessage.
^answerYetAnotherObject
這意味著類名“ClassName”有一個一元消息方法methodSelector,它的定義如上面的代碼所示咒林。
- 二元
ClassName>>+ operand
instanceVariable := instanceVariable + operand.
^self
這意味著類名“ClassName”有一個二元消息方法+ operand,它的定義如上面的代碼所示爷光。
- 關(guān)鍵字
ClassName>>keyword: object message: text
Transcript nextPut: object; nextPut: ' '; nextPutAll: text; cr.
這意味著類名“ClassName”含有一個定義了兩個參數(shù)的關(guān)鍵字消息方法keyword: message:垫竞,它的定義如上面的代碼所示。
7. 賦值
好吧蛀序,我撒謊了欢瞪,這是第七個語法格式。
在前面那個二元消息方法中徐裸,你看到了賦值語句遣鼓,它非常的特別,有兩個原因:
- 因為它可能是一個二進制消息重贺,但事實并非如此骑祟。
- 因為它沒有遵循其他消息的一致形式:
someObject isSentSomeMessage
(注:沒有遵循消息發(fā)送的形式)
8.級聯(lián)
好吧,我又撒謊了气笙,兩次次企。這是第八個語法格式,另一個“一致形式”的例外潜圃。在前面的關(guān)鍵字消息方法中缸棵,你看到了一些分號。分號是這些東西的縮寫:
發(fā)送下一個消息到相同的對象(接受前一個消息的對象)
因此谭期,下面的示例
Transcript nextPut: object; nextPut: ' '; nextPutAll: text; cr.
是指
發(fā)送nextPut: 這個關(guān)鍵字消息(和參數(shù)object)給一個叫做“Transcript”的對象堵第,
然后發(fā)送另一個nextPut:消息(和參數(shù)' ')給同一個對象(Transcript),
然后發(fā)送一個nextPutAll:消息(和參數(shù)text)給相同的對象隧出,
然后發(fā)送一個cr消息給它踏志,
最后,把自己作為這個方法的返回值.(在結(jié)尾隱含了^self
)鸳劳。
4.運算符優(yōu)先級
每個人都喜歡記憶練習(xí)狰贯。你知道多少種優(yōu)先級和結(jié)合性的組合?你應(yīng)該知道多少赏廓?以下是Smalltalk的規(guī)則:
消息 | 優(yōu)先級 |
---|---|
一元 | 高優(yōu)先級 |
二元 | |
關(guān)鍵字 | |
符號 | 低優(yōu)先級 |
其他 | 從左至右 |
當(dāng)然涵紊,括號可以改變優(yōu)先級,就像其他語言幔摸,就是這樣摸柄!
你會覺得不能這樣做,它并不會像你想像的那樣運行:
3 + 4 * 5 = 35 ! ? !
但是它的確這么做了既忆,這才是對的驱负。
這非常的愚蠢嗦玖!
是的,它非常的愚蠢跃脊,把你逼瘋了大約一個星期宇挫,然后它就消失了,就像沒有問題一樣酪术。
(注:因為在Smalltalk中并不遵循四則運算的優(yōu)先級器瘪,而是從左至右運算)
就是這樣
讓我重復(fù)一遍——就是這樣!這就是整個語言绘雁,剩下的就是學(xué)習(xí)庫橡疼,學(xué)習(xí)這門語言的技巧和方言。
現(xiàn)在庐舟,精明的讀者可能在想一些東西欣除,比如:
等一下,獨特的語義形式在哪里挪略?你并沒有講控制流历帚,也沒有涉及到變量、類型瘟檩、分配和重新分配內(nèi)存抹缕、指針、模版墨辛、虛函數(shù)卓研、靜態(tài)方法等等...
很好,不過這是錯誤的睹簇,我涵蓋了所有這些奏赘。好吧,好吧太惠,你贏了磨淌。我從來沒講過關(guān)于變量的任何東西,那是因為它沒有凿渊,除了賦值語句:
instVar1 := 'aString'.
以及臨時符號:
|aTemp anotherTemp|
你可以定義實例變量梁只,通過在browser窗口中輸入它們的名字,以及將類變量輸入到不同的特殊位置埃脏。這里沒有特殊的語義格式搪锣,因為它們不是代碼的一部分,這里沒有類型彩掐,也沒有算法构舟,轉(zhuǎn)換,解引用之類的‘builtin’語法堵幽,這里有分配狗超,不過只能通過消息發(fā)送:
someClassName new
并且這里無法重新分配弹澎,當(dāng)最后一個對象的引用不存在的時候,對象被垃圾回收了努咐。你不能使用*(void *)(0)
苦蒿,其他東西都不存在。
假的麦撵,你說刽肠。你沒有提到檢查控制流的特殊語法。
是的免胃,我沒有,沒有提到任何相關(guān)的語法惫撰,因為你不需要這樣的概念羔沙,就像控制流會打亂你的語法一樣。
oh厨钻,不要覺得不可思議扼雏,當(dāng)然你會覺得,它完全是特別的夯膀。
很抱歉讓你失望了诗充,還記得我說過的“一個塊可以被認(rèn)為是一個臨時類的唯一實例,沒有超類,只有一個方法“嗎诱建?
這就是真相蝴蜓,block還會對其他一些消息作出響應(yīng),就像:
[ ] whileTrue: [ ]
意思是“發(fā)送一個消息給一個對象”俺猿,從字面上發(fā)送一個關(guān)鍵字消息whileTrue:(以及一個參數(shù)(第二個block))給一個對象(第一個block)茎匠。你認(rèn)為當(dāng)它(第一個block)得到這樣一個消息時,會做什么押袍?第一個block將會對自身進行計算(發(fā)送一個value消息給自己)诵冒,如果結(jié)果為真,將會把value消息發(fā)送給第二個block谊惭,然后重新開始汽馋。否則,它會退出并返回false圈盔。
當(dāng)然豹芯,布爾值也有類似的消息方法:
False>>isTrue: aBlock
^nil
False>>ifFalse: aBlock
^aBlock value
False是一個類,它有兩個消息的方法药磺。由于每個對象false都是類False的實例告组,所以沒什么可測試的。它會忽略ifTrue:的請求癌佩,當(dāng)接受ifFalse:的請求時木缝,它總是會做點什么便锨。另一個類,True我碟,跟False有剛好相反的特性放案。(別再想這個了,你會開始認(rèn)為Smalltalk不想某些人認(rèn)為的那么慢矫俺,比如吱殉,它比Java快...)
檢查這個庫,看看如何變更這些簡單的主題來建立你曾經(jīng)想過的那些控制結(jié)構(gòu)厘托,除了一個友雳,沒人會把switch/case語句放在庫中。這會讓初學(xué)者不爽铅匹,以后你會發(fā)現(xiàn)你的方法總是很短押赊,不能容下這樣的語句,如果你想要使用它們包斑,這意味著你的設(shè)計沒有利用好多態(tài)性流礁,所以你應(yīng)該修復(fù)你的程序...
最后一個語法糖是:
'這是一個字符串'
#這是一個符號
這兩者幾乎是相同的,只是后者是一個單例罗丰,有一個唯一的哈希值神帅,用于查找之類的,但你可以忽略它萌抵。
希望這些能幫助你嘗試閱讀Smalltalk程序找御,不過你要當(dāng)心!當(dāng)你理解了所有的這些谜嫉,你可能會發(fā)現(xiàn)很難繼續(xù)使用你現(xiàn)在正在使用的語言...無一例外萎坷,我已經(jīng)警告過你了;-)
下一步是什么?
為了進一步探索Smalltalk沐兰,你可以:
安裝
Object Arts的Dolphin Smalltalk
非常精彩的作品哆档,玩玩它,嘗試一些示例住闯,閱讀教育中心的材料瓜浸。
(這些都是免費的,直到你上癮)
閱讀
comp.lang.smalltalk
Smalltalk: Best Practice Patterns (Kent Beck)
Smalltalk Companion to Design Patterns (Brown, et al)
(和你喜歡的其他Smalltalk書籍)
掌握
Cincom系統(tǒng)的VisualWorks
不可思議的工具集比原,Smalltalk行業(yè)的標(biāo)桿插佛,強大且穩(wěn)定。
一個巨大的類圖書館(a.k.a已經(jīng)為你做了這些工作)
(非商業(yè)版本的VisualWorks也是免費的)量窘。
以上就是reading smalltalk這本小小的smalltalk教程的全部翻譯內(nèi)容雇寇,如果我有翻譯得不好的地方或是錯誤,希望大家可以提出來,我會改掉它锨侯。
smalltalk是一門不同于其他語言的面向?qū)ο笳Z言嫩海,它的所有功能幾乎都是基于消息發(fā)送機制,這是其他語言沒有的特點囚痴。很多設(shè)計模式的誕生其實都是在Smalltalk語言中叁怪,包括四人幫寫的《設(shè)計模式》一書,也使用了C++和Smalltalk共同來描述那些模式深滚。除此之外奕谭,Smalltalk擁有許多方言和不同的環(huán)境,就像Lisp一樣痴荐。上面提到的Dolphin Smalltalk是一個血柳,Squeak也是一個比較活躍的Smalltalk方言和環(huán)境。
如果有機會我會繼續(xù)翻譯Squeak方言的一些簡單教程生兆,希望這些內(nèi)容能幫助大家了解Smalltalk混驰,以及更好的學(xué)習(xí)設(shè)計模式。
本文遵循自由轉(zhuǎn)載-非商用-非衍生-保持署名(知識共享3.0協(xié)議)
This article follows the CC-3.0 License.