scala指导译稿Word文档格式.docx
《scala指导译稿Word文档格式.docx》由会员分享,可在线阅读,更多相关《scala指导译稿Word文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
本文的目的读者是那些已经具有一定编程经验,而想尝试一下Scala语言的人们。
要阅读本文,你应当具有基础的面向对象编程的概念,尤其是Java语言的。
2Afirstexample第一个例子
Asafirstexample,wewillusethestandardHelloworldprogram.Itisnotveryfasci-natingbutmakesiteasytodemonstratetheuseoftheScalatoolswithoutknowingtoomuchaboutthelanguage.Hereishowitlooks:
作为学习Scala的第一部,我们将首先写一个标准的HelloWorld,这个虽然不是很有趣,但是它可以是你对Scala有一个最直观的认识而不需要太多关于这个语言的知识。
我们的Helloworld看起来像这样:
objectHelloWorld{
defmain(args:
Array[String]){
println(”Hello,world!
”)
}
ThestructureofthisprogramshouldbefamiliartoJavaprogrammers:
itconsistsofonemethodcalledmainwhichtakesthecommandlinearguments,anarrayofstrings,asparameter;
thebodyofthismethodconsistsofasinglecalltothepre-definedmethodprintlnwiththefriendlygreetingasargument.Themainmethoddoesnotreturnavalue(itisaproceduremethod).Therefore,itisnotnecessarytodeclareareturntype.
程序的结构对Java程序员来说可能很令人怀念:
它由一个main函数来接受命令行参数,也就是一个String数组。
这个函数的唯一一行代码把我们的问候语传递给了一个叫println的预定义函数。
main函数不返回值(所以它是一个proceduremethod)。
所以,也不需要声明返回类型。
WhatislessfamiliartoJavaprogrammersistheobjectdeclarationcontainingthemainmethod.Suchadeclarationintroduceswhatiscommonlyknownasasingle-tonobject,thatisaclasswithasingleinstance.ThedeclarationabovethusdeclaresbothaclasscalledHelloWorldandaninstanceofthatclass,alsocalledHelloWorld.Thisinstanceiscreatedondemand,thefirsttimeitisused.
对于Java程序员比较陌生的是关于定义了main函数的object语句。
这样的语句定义了一个单例对象:
一个有且仅有一个实例的类。
object语句在定义了一个叫HelloWorld的类的同时还定义了一个叫HelloWorld的实例。
这个实例在第一次使用的时候会进行实例化。
Theastutereadermighthavenoticedthatthemainmethodisnotdeclaredasstatichere.Thisisbecausestaticmembers(methodsorfields)donotexistinScala.Ratherthandefiningstaticmembers,theScalaprogrammerdeclaresthesemembersinsingletonobjects.
聪明的读者可能会发现main函数并没有使用static修饰符,这是由于静态成员(方法或者变量)在Scala中并不存在。
Scala从不定义静态成员,而定义单例object取而代之。
2.1Compilingtheexample编译实例
Tocompiletheexample,weusescalac,theScalacompiler.scalacworkslikemostcompilers:
ittakesasourcefileasargument,maybesomeoptions,andproducesoneorseveralobjectfiles.TheobjectfilesitproducesarestandardJavaclassfiles.
我们使用Scala编译器“scalac”来编译Scala代码。
和大多数编译器一样,scalac接受源文件名和一些选项作为参数,生成一个或者多个目标文件。
scala编译生成的产物就是标准的Java类文件。
IfwesavetheaboveprograminafilecalledHelloWorld.scala,wecancompileitbyissuingthefollowingcommand(thegreater-thansign‘>
’representstheshellpromptandshouldnotbetyped):
假设我们吧上述代码保存为文件HelloWorld.scala,我们使用下面的命令编译它(大于号“>
”表示命令提示符,你不必输入它):
2.2Runningtheexample3
>
scalacHelloWorld.scala
Thiswillgenerateafewclassfilesinthecurrentdirectory.OneofthemwillbecalledHelloWorld.class,andcontainsaclasswhichcanbedirectlyexecutedusingthescalacommand,asthefollowingsectionshows.
这将会在当前目录生成一系列.class文件。
其中的一个名为HelloWorld.class的文件中定义了一个可以直接使用scala命令执行的类。
下文中你可以看到这个例子。
2.2Runningtheexample运行实例
Oncecompiled,aScalaprogramcanberunusingthescalacommand.ItsusageisverysimilartothejavacommandusedtorunJavaprograms,andacceptsthesameoptions.Theaboveexamplecanbeexecutedusingthefollowingcommand,whichproducestheexpectedoutput:
一旦完成编译,Scala程序就可以使用scala命令执行了。
scala的用法和java很相似,并且连选项也大致相同。
上面的例子就可以使用下面的命令运行,这将会产生我们所期望的输出。
scala-classpath.HelloWorld
Hello,world!
3InteractionwithJava与Java交互
OneofScala’sstrengthsisthatitmakesitveryeasytointeractwithJavacode.Allclassesfromthejava.langpackageareimportedbydefault,whileothersneedtobeimportedexplicitly.
Scala的一个强项在于可以很简单的于已有的Java代码交互,所有java.lang中的类都已经被自动导入了,而其他的类需要显式声明导入。
Let’slookatanexamplethatdemonstratesthis.Wewanttoobtainandformatthecurrentdateaccordingtotheconventionsusedinaspecificcountry,sayFrance1.
来看看演示代码吧。
我们希望对日期进行I18N的格式化处理,比如说法国。
Java’sclasslibrariesdefinepowerfulutilityclasses,suchasDateandDateFormat.SinceScalainteroperatesseemlesslywithJava,thereisnoneedtoimplementequiv-alentclassesintheScalaclasslibrary–wecansimplyimporttheclassesofthecor-respondingJavapackages:
Java类库定义了一系列很有用的类,比如Date和DateFormat。
由于Scala于Java能够进行很好的交互,我们不需要在Scala类库中实现等效的代码,而只需直接吧Java的相关类导入就可以了:
importjava.util.{Date,Locale}importjava.text.DateFormatimportjava.text.DateFormat._
objectFrenchDate{
valnow=newDate
valdf=getDateInstance(LONG,Locale.FRANCE)
println(dfformatnow)
1OtherregionssuchasthefrenchspeakingpartofSwitzerlandusethesameconventions.
其他法语国家(例如瑞士法语区)使用同样的格式。
4
Scala’simportstatementlooksverysimilartoJava’sequivalent,however,itismorepowerful.Multipleclassescanbeimportedfromthesamepackagebyenclosingthemincurlybracesasonthefirstline.Anotherdifferenceisthatwhenimportingallthenamesofapackageorclass,oneusestheunderscorecharacter(_)insteadoftheasterisk(*).That’sbecausetheasteriskisavalidScalaidentifier(e.g.methodname),aswewillseelater.
Scala的import语句看上去与Java的非常相似,但是它更加强大。
你可以使用大括号来导入同一个包里的多个类,就像上面代码中第一行所做的那样。
另一个不同点是当导入一个包中所有的类或者符号时,你应该使用下划线(_)而不是星号(*)。
这是由于星号在Scala中是一个有效的标识符(例如作为方法名称)。
这个例子我们稍后会遇到。
TheimportstatementonthethirdlinethereforeimportsallmembersoftheDateFormatclass.ThismakesthestaticmethodgetDateInstanceandthestaticfieldLONGdi-rectlyvisible.
第三行的import语句导入了DataFormat类中的所有成员,这使得静态方法getDateInstance和静态变量LONG可以被直接引用。
InsidethemainmethodwefirstcreateaninstanceofJava’sDateclasswhichbydefaultcontainsthecurrentdate.Next,wedefineadateformatusingthestaticgetDateInstancemethodthatweimportedpreviously.Finally,weprintthecurrentdateformattedaccordingtothelocalizedDateFormatinstance.ThislastlineshowsaninterestingpropertyofScala’ssyntax.Methodstakingoneargumentcanbeusedwithaninfixsyntax.Thatis,theexpression
在main函数中,我们首先建立了一个Java的Date实例。
这个实例默认会包含当前时间。
接下来我们一个使用刚才导入的静态函数getDateInstance定义了日期格式。
最后我们将使用DataFotmat格式化好的日期打印了出来。
最后一行代码显示了Scala的一个有趣的语法:
只有一个参数的函数可以使用(×
×
)。
这样一来,我们的表达式:
dfformatnow
isjustanother,slightlylessverbosewayofwritingtheexpression
其实就是下面的这个冗长的表达式的简洁写法
df.format(now)
Thismightseemlikeaminorsyntacticdetail,butithasimportantconsequences,oneofwhichwillbeexploredinthenextsection.
这看起来是一个语法细节,但是它具有一个重要的后果,我们将在下一节进行说明。
ToconcludethissectionaboutintegrationwithJava,itshouldbenotedthatitisalsopossibletoinheritfromJavaclassesandimplementJavainterfacesdirectlyinScala.
总结一下与Java的交互性,我们应当注意到Scala中可以直接继承或者实现Java中的接口和类。
4Everythingisanobject万物皆对象
Scalaisapureobject-orientedlanguageinthesensethateverythingisanobject,includingnumbersorfunctions.ItdiffersfromJavainthatrespect,sinceJavadis-tinguishesprimitivetypes(suchasbooleanandint)fromreferencetypes,anddoesnotenableonetomanipulatefunctionsasvalues.
Scala作为一个纯面向对象的语言,于是在Scala中万物皆对象,包括数字和函数。
在这方面,Scala于Java存在很大不同:
Java区分原生类型(比如boolean和int)和引用类型,并且不能吧函数当初变量操纵。
4.1Numbersareobjects数字和对象
Sincenumbersareobjects,theyalsohavemethods.Andinfact,anarithmeticex-pressionlikethefollowing:
由于数字本身就是对象,所以他们也有方法。
事实上我们平时使用的算数表达式(如下例)
1+2*3/x
consistsexclusivelyofmethodcalls,becauseitisequivalenttothefollowingexpres-sion,aswesawintheprevioussection:
是由方法调用组成的。
它等效于下面的表达式,我们在上一节见过这个描述。
4.2Functionsareobjects5
(1).+((
(2).*(3))./(x))
Thisalsomeansthat+,*,etc.arevalididentifiersinScala.
这也意味着+,-,*,/在Scala中也是有效的名称。
TheparenthesesaroundthenumbersinthesecondversionarenecessarybecauseScala’slexerusesalongestmatchrulefortokens.Therefore,itwouldbreakthefol-lowingexpression:
在第二个表达式中的这些括号是必须的,因为Scala的分词器使用最长规则来进行分词。
所以他会把下面的表达式:
1.+
(2)
intothetokens1.,+,and2.Thereasonthatthistokenizationischosenisbecause1.isalongervalidmatchthan1.Thetoken1.isinterpretedastheliteral1.0,makingitaDoubleratherthananInt.Writingtheexpressionas:
理解成表达项1.,+,和2的组合。
这样的组合结果是由于1.是一个有效的表达项并且比表达项1要长,表达项1.会被当作1.0,使得它成为一个double而不是int。
而下面的表达式阻止了分析器错误的理解
(1).+
(2)
prevents1frombeinginterpretedasaDouble.
4.2Functionsareobjects函数与对象
PerhapsmoresurprisingfortheJavaprogrammer,functionsarealsoobjectsinScala.Itisthereforepossibletopassfunctionsasarguments,tostoretheminvariables,andtoreturnthemfromotherfunctions.Thisabilitytomanipulatefunctionsasvaluesisoneofthecornerstoneofaveryinterestingprogrammingparadigmcalledfunctionalprogramming.
也许对于Java程序员来说这比较令人惊讶,函数在Scala语言里面也是一个对象。
于是吧函数作为参数进行传递、把它们存贮在变量中、或者当作另一个函数的返回值都是可能的。
吧函数当成值进行操作是函数型编程语言的基石。
Asaverysimpleexampleofwhyitcanbeusefultousefunctionsasvalues,let’sconsideratimerfunctionwhoseaimistoperformsomeactioneverysecond.Howdowepassittheactiontoperform?
Quitelogically,asafunction.Thisverysimplekindoffunctionpassingshouldbefamiliartomanyprogrammers:
itisoftenusedinuser-interfacecode,toregistercall-backfunctionswhichgetcalledwhensomeeventoccurs.
为了解释为什么吧函数当作值进行操作是十分有用的,我们来考虑一个计时器函数。
这个函数的目的是每隔一段时间就执行某些操作。
那么如何吧我们要做的操作传入计时器呢?
于是我们想吧他当作一个函数。
这种目前的函数对于经常进行用户界面编程的程序员来说是最熟悉的:
注册一个回调函数以便在事件发生后得到通知。
Inthefollowingprogram,thetimerfunc