1 / 68

高效的 Scala

高效的 Scala. HENRIK ENGSTRÖM TYPESAFE 软件工程师 @h3nk3. 自我介绍. 从 1998 年开始做咨询 — 主要针对 Java. 从 2010 年开始进行 Scala 编程. 从 2011 年开始为 Typesafe 公司工作. Akka 团队荣誉会员. Typesafe 控制台技术负责人. 阿森纳球迷 + 武术家. 关于 Typesafe. Typesafe 平台 Play 、 Akka 、 Scala 、 Scala IDE 、 Slick 、 SBT 等 订阅 培训和咨询.

marcos
Download Presentation

高效的 Scala

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 高效的 Scala HENRIK ENGSTRÖM TYPESAFE 软件工程师 @h3nk3

  2. 自我介绍 • 从 1998 年开始做咨询 — 主要针对 Java • 从 2010 年开始进行 Scala 编程 • 从 2011 年开始为 Typesafe 公司工作 • Akka 团队荣誉会员 • Typesafe 控制台技术负责人 • 阿森纳球迷 + 武术家

  3. 关于 Typesafe • Typesafe 平台 • Play、Akka、Scala、Scala IDE、Slick、SBT 等 • 订阅 • 培训和咨询

  4. 议题 • 基础知识 • Scala 中的对象定位 • 隐式 • 类型 • 集合 • 模式匹配 • 函数式编程

  5. 基础知识

  6. // REPL = Read Eval Print Loop $scala_home/bin/scala WelcometoScalaversion2.10.0 scala>println("Hello, world!") Hello,world! scala> 使用 REPL

  7. // Put JAR files in scala_home/lib to get access $scala_home/bin/scala WelcometoScalaversion2.10.0 scala>importcom.x.y.z.MyClass scala>valinstance=newMyClass scala>instance.myMethod REPL 和 JAR

  8. REPL 2013 • IDE 工作表 • Scala IDE: 棒极了 • IntelliJ: 很好

  9. // JAVA Stringresult=null; if(z<9)result="<9"elseresult=">=9"; System.out.println("Result: "+result); // SCALA println("Result: "+if(z<9)"<9"else">=9")) 表达式与语句

  10. // What type is variable quiz? varx=1 valquiz=while(x<10){ println("X is: "+x) x+=1 } 语句突击测试 (Pop Quiz) • Scala 中的所有表达式返回一个类型

  11. // Don’t tell the computer how to fish importscala.collection.mutable.{HashSet=>MHS} deffindPeopleInCity(c:String,ppl:Seq[People]): Set[People]={ valfound=newMHS[People]() for(p<-ppl) for(a<-p.address) if(a.city==c)found.put(p) found } 请注意无钓鱼说明!

  12. deffindPeopleInCity(c:String,ppl:Seq[People]): Set[People]={ for{ p<-ppl.toSet[People] a<-p.address ifa.city==c }yieldp } // SQL LIKE SYNTAX; FROM, WHERE, AND, SELECT 而只是点鱼

  13. // 1) Mutable code leads to cloning // 2) Cloning leads to performance degradation // => Mutable code leads to worse performance classFootballer{ privatevarcars=Array[Car]() defsetCars(c:Array[Car]):Unit= cars=c.clone defgetCars:Array[Car]=cars.clone } 保持不可变

  14. // Safer code - use immutable collection classFootballer{ privatevarcars=Vector.empty[Car] defsetCars(c:Vector[Car])=cars=c defgetCars:Vector[Car]=cars } 保持不可变

  15. // Case classes make the class immutable scala>caseclassCar(brand:String) scala>caseclassFootballer(name:String,team: String,cars:Vector[Car]=Vector.empty) scala>varjw=newFootballer("Jack Wilshire", "Arsenal") Footballer(JackWilshire,Arsenal,Vector()) scala>jw=jw.copy(cars=Vector(Car("Porsche"))) Footballer(JackWilshire,Arsenal, Vector(Car(Porsche))) Case 类 ftw

  16. 不可变的优势 • 简单均等 • 简单散列代码 • 无需锁定 • 无防御性复制 • Scala Case 类 • 自动均等 + 散列代码 (Murmur) • 还有很多其他好处(例如复制)

  17. // Sometimes local mutability makes sense importscala.collection.mutable.ArrayBuffer classMyClass{ deftheData:Seq[Int]={ valbuffer=newArrayBuffer[Int]() populateData(buffer) buffer.toSeq } } 局部可变性

  18. // A classic game of null defauth(usr:String,pwd:String):Privileges= if(usr==null||usr.isEmpty|| pwd==null||pwd.isEmpty|| !validCredentials(usr,pwd)) withPrivileges(Anonymous) else privilegesFor(usr) 使用选项

  19. defauth(usr:Option[String],pwd:Option[String]): Privileges={ valprivileges:Option[Privileges]={ u<-usr p<-pwd if(!u.isEmpty&&!p.isEmpty) ifcanAuthenticate(u,p) }yieldprivilegesFor(u) privilegesgetOrElsewithPrivileges(Anonymous) } 使用选项

  20. 对象定位

  21. traitSquareShape{ valwidth:Int valheight:Int valarea:Int=width*height } classRect(w:Int,h:Int)extendsSquaredShape{ overridevalwidth=w overridevalheight=h } scala>valr1=newRectangle(1,314) scala>r1.height res0:Int=314 scala>r1.area res1:Int=0 抽象成员的 val

  22. Scala 初始化顺序 • 摘自 Scala 规范(第 5.1 节) • http://www.scala-lang.org/docu/files/ScalaReference.pdf • 首先评估超类构建函数 • 然后是模板线性化中的所有基类…… • 最后评估语句序列状态

  23. traitSquareShape{ defwidth:Int defheight:Int defarea:Int=width*height } classRect(w:Int,h:Int)extendsSquaredShape{ overridevalwidth=w overridevalheight=h } // or even better caseclassRect(width:Int,height:Int)extends SquaredShape def is much better

  24. // Non-trivial return types should always be // annotated! defconvert(x:Int)=xmatch{ case1=>1.toChar case2=>true casez=>z.toByte } defconvert(x:Int):AnyVal=xmatch{ 为您的 API 加批注

  25. 组合与继承 • 与继承相比,更偏好组合 • 易于修改(例如 DI) • 组合可在 Scala 中使用继承 • 引向著名的“蛋糕”模式

  26. traitUserRepoComponent{ defuserLocator:UserLocator defuserUpdater:UserUpdater traitUserLocator{ deffindAll:Vector[User] } traitUserUpdater{ defsave(user:User) } } 让我们来烘培一块“蛋糕”

  27. traitJPAUserRepoComponentextendsUserRepoComponent{ defem:EntityManager defuserLocator=newJPAUserLocator(em) defuserUpdater=newJPAUserUpdater(em) classJPAUserLocator(em:EntityManager)extendsUserLocator{ deffindAll:Vector[User]=em.createQuery("from User", classOf[User]).getResultList.toVector } classJPAUserUpdater(em:EntityManager)extendsUserUpdater{ defsave(user:User)=em.persist(user) } } 正在烘培

  28. traitUserServiceComponent{ defuserService:UserService traitUserService{ deffindAll:Vector[User] defsave(user:User):Unit defcheckStatusOf(user:User):String } } 服务层

  29. traitDefaultUserServiceComponentextends UserServiceComponent{ this:UserRepositoryComponent=> defuserService=newDefaultUserService classDefaultUserServiceextendsUserService{ deffindAll=userLocator.findAll defsave(user:User)=userUpdater.save(user) defcheckStatus(user:User)= s"User $user seems okay to me" } } 服务层实现

  30. objectMyApplicationextendsApplication{ • valcompService= • newDefaultUserServiceComponent • withJPAUserRepositoryComponent{ • defem= • Persistence.createEntityManagerFactory( • "cakepattern").createEntityManager() • } • valservice=compService.userService • // use the service • } 投入使用

  31. classMyTestextendsWordSpecwithMustMatcherswith Mockito{ traitMockedEntityManager{ defem=mock[EntityManager] } "service"must{ "return all users"in{ valcompService= newDefaultUserServiceComponent withJPAUserRepositoryComponent withMockedEntityManager // perform tests } } 进行测试

  32. 隐式

  33. 有何作用? • 在特定上下文中移除样板代码 • 编译时安全 • 但是必须明确

  34. traitAutoRepository{ deffind(regId:String)(implicitdbId:DBId): Option[Car] deffindAll(country:String)(implicitdbId:DBId): Seq[Car] } classDefaultAutoRepositoryextendsAutoRepository{ deffind(regId:String)(implicitdbId:DBId): Option[Car]={// ... } deffindAll(country:String)(implicitdbId:DBId): Seq[Car]={// ... } } 示例

  35. // Anti pattern classCarFinder{ valdbId=DbId("Dealer1") valrepo=newDefaultAutoRepository defgetCar(regId:String):Option[Car]= repo.find(regId)(dbId) deflistCars(country:String):Seq[Car]= repo.findAll(country)(dbId) } 示例(续)

  36. // Use implicits => much cleaner code classCarFinder{ implicitvaldbId=DbId("Dealer1") valrepo=newDefaultAutoRepository defgetCar(regId:String):Option[Car]= repo.find(regId) deflistCars(country:String):Seq[Car]= repo.findAll(country) } 示例(续)

  37. 编译器练习 • 隐式作用域 • 词法: 当前作用域、显式导入、通配符导入 • 部分类型的伴生对象: 类型的伴生对象、参数类型的伴生对象、嵌套类型的外部对象 • 编译时可能会消耗大量资源,应谨慎使用

  38. traitLogger{deflog(msg:String)} objectLogger{ implicitobjectDefaultLoggerextendsLogger{ deflog(msg:String)=println("DL> "+msg) } deflog(msg:String)(implicitlogger:Logger)={ logger.log(msg) } } 隐式值

  39. scala>Logger.log("a small test") DL> a small test scala>classMyLoggerextendsLogger{ deflog(msg:String)=println("ML:>> "+msg) } scala>implicitdefmyLogger=newMyLogger scala>Logger.log("another test") ML:>> another test 隐式值

  40. 隐式智慧? deech @deech 调试 #scala 隐式内容如同 在一个拥挤的房间中寻找 farter

  41. 类型特性

  42. // "describes generic interfaces using type // parameters such that the implementations can // be created for any type" traitEncodable[T]{ deffrom(t:T):String defto(s:String):T } objectEncodable{ implicitobjectIntEncoderextendsEncodable[Int]{ deffrom(i:Int):String="int"+i defto(s:String):Int= s.substring(s.indexOf("int")+3,s.length).toInt } } 即,类型类

  43. classMyHandler{ defconvert[T](t:T)(implicitenc:Encodable[T]): String=enc.from(t) defconvert[T](s:String)(implicitenc: Encodable[T]):T=enc.to(s) } scala>valmyHandler=newMyHandler scala>myHandler.convert(12345) res0:String=int12345 scala>myHandler.convert(res0) res1:Int=12345 使用示例

  44. scala>myHandler.convert(12345L) <console>:15: error: could not find implicit value for parameter encoder: Encodable[Long] scala>implicitobjectLongEncextends Encodable[Long]{ deffrom(l:Long):String="long"+l defto(s:String):Long= s.substring(s.indexOf("long")+4, s.length).toLong} scala>myHandler.convert(12345L) 示例(续)

  45. 集合

  46. 集合概述

  47. 不可变集合

  48. 可变集合

  49. // It is absolutely *awesome* scala>valseq=Seq() scala>seq. ++ ++: +: /: /:\ :+ :\ addString aggregate andThen apply applyOrElse asInstanceOf canEqual collect collectFirst combinations companion compose contains containsSlice copyToArray copyToBuffer corresponds count diff distinct drop dropRight dropWhile endsWith exists filter filterNot find flatMap flatten fold foldLeft foldRight forall foreach genericBuilder groupBy grouped hasDefiniteSize head headOption indexOf indexOfSlice indexWhere indices init inits intersect isDefinedAt isEmpty isInstanceOf isTraversableAgain iterator last lastIndexOf lastIndexOfSlice lastIndexWhere lastOption length lengthCompare lift map max maxBy min minBy mkString nonEmpty orElse padTo par partition patch permutations prefixLength product reduce reduceLeft reduceLeftOption reduceOption reduceRight reduceRightOption repr reverse reverseIterator reverseMap runWith sameElements scan scanLeft scanRight segmentLength seq size slice sliding sortBy sortWith sorted span splitAt startsWith stringPrefix sum tail tails take takeRight takeWhile to toArray toBuffer toIndexedSeq toIterable toIterator toList toMap toSeq toSet toStream toString toTraversable toVector transpose union unzip unzip3 updated view withFilter zip zipAll zipWithIndex 了解和学习 API

  50. 给 Java 开发人员的信息 • 使用 Vector而不是 List • 它更快 • 它对内存的使用更高效

More Related