smalltalk超简明教程Word文档格式.docx
《smalltalk超简明教程Word文档格式.docx》由会员分享,可在线阅读,更多相关《smalltalk超简明教程Word文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
1或者多个
do:
,between:
and:
传输一个或多个参数时,需要使用关键字消息。
每一个参数前面需要添加关键字。
Smalltalk不使用{}和;
分割参数。
例子:
();
(10);
(20,anotherAccount)
(anotherAccount);
myAccountgetBalance
myAccountsetBalance:
10
myAccounttransfer:
20to:
anotherAccount
myAccount=anotherAccount
●运算优先级:
一元运算符(首先运算)
二元运算符(其次运算)
关键字(最后运算)
在同等优先级下,运算是从左到右
3+5*6
●常量
Smalltalk中整数类型,字符类型,字符串类型,布尔类型,浮点数类型和双精度浮点数类型都是头等类对象。
整数类型是无限精度的,会按需自动增长,而不会溢出(译者注:
跟内存大小有关)。
实际上,Smalltalk中没有char类型,byte类型,short类型,int类型或者long类型的相对应的类型。
它们都是整数类型。
5
01230
8r1230
0x7f
16r7f
<
无对应物>
3r21012(你可以选择你想用的基数)
200L
2e-5
2e-5d
2d-5
'
h'
$h
\u03A9'
Charactervalue:
16r3A9
"
hello"
hello'
can'
t"
t'
●特定词
Smalltalk中,nil引用一个真实的对象,它是UndefinedObject类的实例。
true是True类的实例,flase是Flase类的实例
this
self
null
nil
true
false
super
base(C#)
●方法返回
returnvalue;
^value
●级联
myAccount
deposit:
20;
transfer:
anotherAccount
●注释
/*comment*/
etTime();
endTime=
newGregorianCalendar().getTime();
}
Reservationclassmethods:
new
^supernewinitialize
Reservationinstancemethod:
initialize
startTime:
=Timestampnow.
endTime:
=Timestampnow
●块
Smalltalk称对象为块,它是包含可执行代码的对象。
Java中最相似的东西是匿名内部类,C#中,跟匿名托管相类似。
执行“块”无需参数,可以向它发送一个value消息
|block|
block:
=[3+4].
blockvalue"
answeris7"
块可以有参数,每一个块参数的声明必须以冒号(:
)开头,以竖线(|)表示参数列表的结束和块代码的开始。
=[:
x:
y|x*2+y].
blockvalue:
5value:
3"
answeris13"
●语法结束
到此为止,我们已经介绍了Smalltalk所有的语法。
其余的事情属于类库部分。
你是否注意到我们是否忘记了某些事情if-then-else或者while循环Smalltalk只使用块和普通的消息发送。
●控制结构
Smalltalk没有在语言中内置控制结构。
Smalltalk使用向true或者flase对象发生消息作为替代。
if(tries>
5)
return"
Toomanytries"
;
else
Tryingagain"
tries>
5
ifTrue:
[^'
Toomanytries'
]
ifFalse:
Tryingagain'
注意^表示从方法返回,不只是适用于块。
●循环
Smalltalk使用块做循环。
由于块是对象,所有我们可以先他们发生消息
inttries=0;
while(tries<
=5){
tryAgain();
tries++;
|tries|
tries:
=0.
[tries<
=5]whileTrue:
[
selftryAgain.
=tries+1]
alternatively:
5timesRepeat:
[selftryAgain]
注意timesRepeat:
是整数类型能理解的消息。
它简化了块执行的次数
smalltalk入门
原文标题:
ICanReadC++andJavaButICan’tReadSmalltalk
原文作者:
WilfLaLonde
原文链接:
简介
有很多人告诉我他很熟悉C++或Java,但是却完全读不懂Smalltalk的代码。
对于他们来说,Smalltalk简直无法理解!
对于这个问题我考虑了很久然后得到的结论是他们是对的。
如果我随便挑出一些自己多年以前写的Smalltalk代码,然后假设我只明白Java去阅读的时候,我确信我是无法理解那些代码的。
其实要读懂Smalltalk只须了解一些非常简单的概念,当然有些概念也是比较微妙。
如果“Johnny读不懂Smalltalk代码”,我有办法。
我的办法就是通过实际的例子来帮助新手快速理解Smalltalk的概念。
我假设读者了解什么是面向对象变成,对于那些已经掌握Smalltalk的读者也请先假装一会没有学过smalltalk。
如此简单的文法
有些语法是很容易理解的,例如使用双引号来标识注视块;
单引号标示字符串,单个字符前面加$(例如:
$x标示字符“x”)。
除此之外,还有symbol的概念,这是一个特殊的字符串,在整个内存中是唯一的。
当源代码被编译的时候,编译器会搜索整个内存,如果发现相同的symbol存在则使用已存在的那个。
有理数并不节省内存,但是相对于symbol而言处理速度更快(稍候解释)。
“thisisacomment”
‘thisisastring’
#’thisisasymbol’
#thisIsASymbolToo
对于赋值操作和等于号,差别不是很大。
:
=^result
在执行的时候,t和self,a和angle,v和vector有一对一的映射关系。
需要注意的是^表示返回,相当于return关键字。
变量self则相当于this。
如果方法的最后没有显式的返回表达式,则却省为^self。
也就是说,不写return语句也不会有什么问题。
这同时也意味着无论调用者是否需要,类方法都将返回一个对象的引用。
事实上,Smalltalk的语法要求self不能出现在函数名的最前面,如下所示:
rotateBy:
anglearound:
vector
|result|
result:
=COMPUTEANSWER.
^result
Smalltalk的这种关键字语法的优点就是,针对不同的方法可以使用不同的关键字。
例如,我们可以像下面这样定义第二个函数:
trotateAround:
vectorby:
angle
没有必要刻意的去记住参数的顺序,因为关键字暗示了他们的顺序。
当然,作为编程者也有可能滥用关键字。
例如,如果我们像下面这样定义关键字:
trotate:
angleand:
vector
很明显,使用这个函数的人无法通过关键字确定参数的顺序。
这是很不好的编程风格。
如果只有一个参数的话,则无所谓。
但是我们仍然需要只有一个关键字的方法名:
trotateAroundXBy:
angle
trotateAroundYBy:
我更倾向于将关键字理解为一种说明性的参数。
但是如果没有参数的时候该怎么办呢
tmakeIdentity:
collectionadd:
transformation.
哦,你可能会很奇怪这里怎么可能有一个dollars消息,其实这没什么特别的。
为了使这个表达式合法,Integer类中必须有一个dollars方法的定义(100将被当作Integer对象处理)。
虽然在标准的Smalltalk环境中并没有这样的定义,但是我们可以自己添加。
Smalltalk的基类可以简单的通过定义新的继承类来扩展。
因此,句号是表达式的终结符,但是在最后一行表达式后面也可以省略(因此你也可以把句号当成表达式之间的分隔符)。
但是分号也是合法的,他用在层跌消息语法中(往一个对象中一次发送多个对象的语法)。
例如:
|p|
p:
=Clientnew.
pname:
'
Jack'
.
page:
32.
paddress:
Earth'
.
对于上面这样一个表达式我们应该如下编写:
p
name:
age:
32;
address:
或者干脆写成:
=Clientnew
上面的例子中格式并没太大关系,只要愿意我们甚至可以把所有的句子都写成一行。
很关键的分号指出了前一条消息发送到接受对象并使其状态发生变化之后,下一条消息将被继续发到这个接受对象。
(而不是发到上一条消息的返回值对象,上条消息的返回值将被抛弃或者忽视)。
在最后一个例子当中,new被发送到类来生成一个实例(作为返回值)。
然后“name:
’Jack’”被发送到这个实例。
第一个分号表示“name:
’Jack’”消息返回的结果将被忽略,紧接着“age:
32”被发送到先前的实例。
第二个分号表示“age:
32”返回的结果被忽略,紧接着“address:
’Earth’”被发送到先前的实例。
最后,“address:
’Earth’”返回的结果被保存到变量p。
修改接收者属性的类方法通常都返回接收者自身。
因此变量p就最终被绑定到了被修改了好几次的新生成的类实例对象上。
我们可以将上面的分号替换成“ANDALSO”就会感觉很容易理解这段代码的意思了。
在Smalltalk中类似这样向同一个对象连续发送消息的语法称作层跌消息。
分号也可以在子表达式中使用,例如“p:
=(Clientnewname:
age:
address:
)”—注意这里的括号。
Get/Set方法使用与实例变量相同的名称
类似name,age,address这样的类实例变量在Smalltalk中全都属于私有变量。
但是类方法可以提供对这些变量的访问。
在C++中(Java也类似),例如,我们可以定义下面这样的访问类实例变量的方法:
longgetAge(){returnage;
voidsetAge(longnewAge){age=newAge;
}
如果你有好几打的类,并且你使用上面这样的编码约定,你将会发现最终你的代码中有一大堆的以get和set打头的类方法。
当然,如果你碰巧决定通过去掉这些重复的前缀以便让类方法名短些,你会发现C++的编译器将会无法编译,因为他无法从名称区分变量和函数。
但是Java的编译器对于下面这样的代码则没有什么问题。
longage(){returnage;
voidage(longnewAge){age=newAge;
你能区分变量age和消息age吗你应该可以。
当你使用这条消息的时候,你需要加上括号,就像“age()或者age(22)”;
当你引用这些变量的时候,则不需要使用括号。
同样的类方法在Smalltalk中可以写成下面这样:
age^age
newAgeage:
=newAge
不过,我们通常通过写成两行来让代码更可读:
age
^age
newAge
age:
=newAge
在Smalltalk中没有括号可以帮助你区分变量和消息,但是要区分也不是很难。
如果你行的话,应该可以看出下面这句话中哪些是变量,哪些是方法:
ageageage:
ageage+ageage
好吧,答案是3;
第一个age必然是一个变量,第四个也是(每个关键字后面都必须是一个子表达式;
所有的表达式都必须以变量开头),还有第七个(在一个二元操作符后面,也必须是一个子表达式)。
用更简单典型的例子应该更容易理解,如下:
namesizeArraysareconceptuallyorderedcollectionsthatcan’tchangesize.
|ab|
=OrderedCollectionnew
add:
#red;
#green;
yourself.
b:
=Dictionarynew
at:
#redput:
#rouge;
#greenput:
#vert;
Ineachoftheaboveassignments,thevariableisboundtotheresultofthelastmessageexecuted;
.,theresultof“yourself”whichis,hopefully,thenewlycreatedcollection.Message“yourself”isdesignedtoreturnthereceiver(almostlikeano-op)but“add:
”and“at:
put:
”donot(theyreturntheirlastparameter).Sowithout“yourself”,wewouldbind“a”to#green”and“b”to#vert.
Ideliberatelyusedcascadingaboveinordertoexplainwhy“yourself”isusedatallsinceitappearsinisolatedmethodsinthebuilt-inclasses.
ThebigadvantagetoSmalltalkcollectionsisthatyoucanputanyobjectswhatsoeverinthecollections.
Eventhekeysindictionariescanbeanytypeofobject.Also,theobjectsinaspecificcollectiondon’thavetobethesametype;
theycanallbedifferenttypes.Wedon’tneedtoinventnewkindsofcollectionsjustbecausewewanttoaccumulateinstancesofabrandnewclass.
Orderedcollectionscanbeaccessedlikearrays;
.,“aat:
1”indexedstartingat1.Dictionariesareaccessedthesamewaytoo;
.,“bat:
#red”.Buttherearemanyapplicationswherewedon’tneedtodealwiththekeys.Forthese,thereareverysimplyloopingfacilitiesthatiteratethroughtheitems;
.,
ado:
[:
item|
USEitemFORSOMETHING].
bdo:
Loopvariable“item”getstheelementsofthecollectionone-by-oneeveniftheyarealldifferenttypes.
Ifnecessary,wecaneasilyfindoutwhatsomethingisatexecutiontime;
.,“itemisKindOf:
Boat”returnstrueorfalse.Therearealsomanyspecial-casequerymessageslike“itemisCollection”or“itemisNumber”.Therearealsomanyloopingconstructsthatcreateandreturnnewcollectionssuchas
c:
=clientsselect:
client|clientnetWorth>
500000].
d:
=clientscollect:
client|clientname].
Inthefirstcase,wegetasubcollectionofthoseclientsthatareprettyrich.Inthesecond,wegetacollectionofnames(theoriginalcollectionwasacollectionofclients).
序列化抽象无须创建新的class
Everynowandthen,areaderwillfindcodethatlookslike
stuffvalue:
xvalue:
yvalue:
z
wherethekeywordsareall“value:
”.Thisclearlylooksuselessandbewilderingtoanon-Smalltalkreader.Whatishappeningisthattheprogrammerhas(typically)createdanewabstractionfacility.
LetmeexplainthisfundamentalcapabilitythatonlySmalltalksupportswithachallenge.GiventhatwehavealreadyintroducedtheClientclassearlier,supposethatwewantasimplefacilityforloopingthroughanindividualclient’sparts;
.,wewantthelooptofirstgiveusthename,thenthenexttimearound,wewanttheage,andfinallywewanttheaddress.
TheconventionalsolutioninC++andJavaistocreateaspecialstreamclassorenumerator,saycalledClientIterator,withfacilitiestoinitializeit,toaskitifitisattheend,and,ifnot,toaskforthenextobjectintheiterator.Thenwecanhavealoopthatsetsuptheiteratorand,whilenotattheend,getsthenextobjectandprocessesit.Theadvantageoftheiteratoristhatitcanprovideitsownvariablesforkeepingtrackofwhereit’satinthesequencingprocess;
.,it’snotnecessarytoextendtheClientclasswith“temporary”instancevariablesneededforiterating.
Anexamplepieceofcodethatmightmakeuseof