Successfully reported this slideshow.
Your SlideShare is downloading. ×
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
functional-scala
functional-scala
Loading in …3
×

Check these out next

1 of 79 Ad

More Related Content

Viewers also liked (20)

Advertisement

Recently uploaded (20)

Advertisement

Scala

  1. 1. println("Hello Scala") [email_address] Jul 12, 2011
  2. 2. 一、什么是 scala 二、谁在用 scala 三、为什么要用 scala 四、快速入门 五、加点难度 六、更进一步
  3. 3. 什么是 scala http://www.scala-lang.org/ scala 是 Scalable Language 的简写,由 Martin Odersky (Generic Java 的作者 ) 发明,目的就是创造一个 jvm 上的高度可扩展的语言。 2003 诞生,前身是 Pizza ( 1996 ,晚 java 一年)、 Funnel ,最新版本是 2.9.0.1 ,它具有以下特性: 1.It has an event-based concurrency model. (基于事件的并行模式) 2.It supports both an imperative style and a functional style. (支持命令式和函数式编程) 3.It is purely object-oriented. (纯粹的面向对象) 4.It intermixes well with Java. (和 java 的完美混合) 5.It enforces sensible static typing. (强制静态) 6.It is concise and expressive. (简洁且易于表达的) 7.It is built on a small kernel. (只有一个很小的核心) 8.It is highly scalable, and it takes less code to create high-performing applications. (易于扩展,只用很少的代码即可写出高性能的程序。 type less , do more )
  4. 4. 什么是 scala 之 FP <ul><li>Functional Programming 函数式编程 , 和命令式编程相比,函数式编程强调函数的计算比指令的执行重要。和过程化编程相比,函数式编程里,函数的计算可随时调用。函数式编程常被认为严重耗费在 CPU 和存储器资源 </li></ul><ul><li>1. 函数是头等公民( class 、 object 、 xml ),正如 int 之类的,你可以将函数当做参数来传递或返回,即高阶函数;也可以在函数中定义函数,可以定义匿名函数。 </li></ul><ul><li>2. 不可变数据结构,也就是说程序的操作是对数值的映射修改而不是改数据,同时任何方法都不容许出现副作用,它们只通过参数和返回值与环境进行交互,应该是引用透明的) </li></ul><ul><li>函数编程语言最重要的基础是 λ 演算(又被称为最小的通用程序设计语言 ),它包括一条变换规则(变量替换)和一条函数定义方式,这种演算可以用来清晰地定义什么是一个可计算函数 </li></ul><ul><li>函数式编程一般会采用递归而不是循环,纯函数编程不含有变量和副作用,所以在并行运算中将有很大的发挥空间,最早的是 Lisp (现在是一个家族),后来有 Haskell 、 Clean 、 Erlang 、 ML (也是一个家族,如 Ocaml )、 F# (基于 Ocaml )和 Miranda 等。 </li></ul>
  5. 5. 谁在用 scala <ul><li>Twitter </li></ul><ul><li>LinkedIn </li></ul><ul><li>Novell </li></ul><ul><li>FourSquare </li></ul><ul><li>Sony </li></ul><ul><li>Siemens </li></ul><ul><li>yammer </li></ul><ul><li>vmware </li></ul><ul><li>opower </li></ul><ul><li>typesafe </li></ul><ul><li>qiyi ( baidu ) ... </li></ul>
  6. 6. 为什么要用 scala <ul><li>scala 混合了 FP 和 OOP ,基于 actor 的事件传导式多线程编程,完全基于 java ,可以利用所有 java 已有的东西,静态且强类型,超实用的 api ,重载操作符,基于 trait 的多重继承的混入机制, xml 、闭包、模式匹配等的语言级别支持,可以直接用来写脚本,写属于你的 DSL ,比 jvm 上第二大的语言 groovy 有着更高的性能,更易调试,语法更简洁而优雅,相对来讲有着高发展速度 </li></ul><ul><li>( Eric Raymond 的教堂集市学) </li></ul><ul><li>你可以在任何使用 java 的地方来使用 scala ,所有的,包括 android , .net 等。可以写出很好的并行程序,也可以写出属于自己的 DSL </li></ul><ul><li>http://www.assembla.com/wiki/show/scala-ide/Developing_for_Android </li></ul><ul><li>少打好多字,比 groovy 还少, type less , do more </li></ul><ul><li>Akka 、 lift </li></ul><ul><li>PS :这是一群聪明人写的聪明语言,但是细节做得很差 </li></ul>
  7. 7. 为什么要用 scala <ul><li>举几个例子: 留个作业:等分享完了再看一下这块例子的代码 </li></ul><ul><ul><li>快排 </li></ul></ul><ul><ul><ul><li>def qs(aa:Array[Int]):Array[Int]={ </li></ul></ul></ul><ul><ul><ul><li> if(aa.length<=1)aa </li></ul></ul></ul><ul><ul><ul><li> else { </li></ul></ul></ul><ul><ul><ul><li> val pivot=aa(aa.length/2) </li></ul></ul></ul><ul><ul><ul><li> Array.concat( </li></ul></ul></ul><ul><ul><ul><li> qs(aa.filter(pivot>)), </li></ul></ul></ul><ul><ul><ul><li> aa.filter(pivot==), </li></ul></ul></ul><ul><ul><ul><li> qs(aa.filter(pivot<)) </li></ul></ul></ul><ul><ul><ul><li> ) </li></ul></ul></ul><ul><ul><ul><li> } </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>多个变量快速赋值 </li></ul></ul><ul><ul><li>val (a,b,c)=(List(1,3),8, &quot;fds&quot; ) </li></ul></ul><ul><ul><ul><li>会得到 </li></ul></ul></ul><ul><ul><ul><ul><li>a: List[Int] = List(1, 3) </li></ul></ul></ul></ul><ul><ul><ul><ul><li>b: Int = 8 </li></ul></ul></ul></ul><ul><ul><ul><ul><li>c: java.lang.String = fds </li></ul></ul></ul></ul><ul><ul><li>val a,b,c=0 </li></ul></ul><ul><ul><ul><li>会得到 </li></ul></ul></ul><ul><ul><ul><ul><li>a: Int = 0 </li></ul></ul></ul></ul><ul><ul><ul><ul><li>b: Int = 0 </li></ul></ul></ul></ul><ul><ul><ul><ul><li>c: Int = 0 </li></ul></ul></ul></ul>
  8. 8. 为什么要用 scala <ul><li>举几个例子: </li></ul><ul><ul><li>一个 List[String] 中是否有大写字母 </li></ul></ul><ul><ul><ul><li>xs.exists(_.exists(_.isUpperCase)) </li></ul></ul></ul><ul><ul><li>统计一个全数字文件的总和 </li></ul></ul><ul><ul><ul><li>import scala.io.Source </li></ul></ul></ul><ul><ul><ul><li>val lines=Source.fromFile( &quot;d:/1.txt&quot; ).getLines </li></ul></ul></ul><ul><ul><ul><li>(0 /: lines)(_.toInt + _.toInt) </li></ul></ul></ul><ul><ul><li>解析 xml </li></ul></ul><ul><ul><ul><li>import scala.xml.XML </li></ul></ul></ul><ul><ul><ul><li>val xml=XML.loadFile(&quot;therm1.xml&quot;) </li></ul></ul></ul><ul><ul><li>定义一个得瑟留言类 </li></ul></ul><ul><ul><ul><li>class Comment(username:String,content:String,times:Int){ </li></ul></ul></ul><ul><ul><ul><li>require(times> 0) </li></ul></ul></ul><ul><ul><ul><li>def this (username:String)= this (username, &quot; 书记万税 &quot; ,10) </li></ul></ul></ul><ul><ul><ul><li>override def toString = username+ &quot; 喊了 &quot; +times+ &quot; 遍: &quot; +content </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  9. 9. 为什么要用 scala <ul><li>举几个例子: </li></ul><ul><ul><li>投连险有这么一段代码 </li></ul></ul><ul><ul><ul><li>private static String[] supportEnvs = new String[] { &quot;dev&quot;, &quot;dly&quot;, &quot;prd&quot;, &quot;tst&quot;, &quot;pre&quot;, &quot;perf&quot; }; </li></ul></ul></ul><ul><ul><ul><li>... </li></ul></ul></ul><ul><ul><ul><li>for (String s : supportEnvs) { </li></ul></ul></ul><ul><ul><ul><li>if (s.equals(_envName)) { </li></ul></ul></ul><ul><ul><ul><li>envName = _envName; </li></ul></ul></ul><ul><ul><ul><li>break; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>很麻烦,不是么,那么放到 scala 里 </li></ul></ul></ul><ul><ul><ul><li>def supportEnvs =List( &quot;dev&quot; , &quot;dly&quot; , &quot;prd&quot; , &quot;tst&quot; , &quot;pre&quot; , &quot;perf&quot; ) </li></ul></ul></ul><ul><ul><ul><li>if (supportEnvs contains _envName) envName = _envName </li></ul></ul></ul>
  10. 10. 为什么要用 scala <ul><li>举几个例子: </li></ul><ul><ul><li>class MyClass( var index: Int, var name: String) </li></ul></ul><ul><ul><li>看看生成的代码 </li></ul></ul><ul><ul><ul><li>import scala.ScalaObject; </li></ul></ul></ul><ul><ul><ul><li>import scala.reflect.ScalaSignature; </li></ul></ul></ul><ul><ul><ul><li>@ScalaSignature(bytes= &quot; 略 ...&quot; ) </li></ul></ul></ul><ul><ul><ul><li>public class MyClass implements ScalaObject{ </li></ul></ul></ul><ul><ul><ul><li>private int index; </li></ul></ul></ul><ul><ul><ul><li>private String name; </li></ul></ul></ul><ul><ul><ul><li>public int index(){ return this .index; } </li></ul></ul></ul><ul><ul><ul><li>public void index_$eq(int paramInt) { this .index = paramInt; } </li></ul></ul></ul><ul><ul><ul><li>public String name() { return this.name; } </li></ul></ul></ul><ul><ul><ul><li>public void name_$eq(String paramString) { this .name = paramString; } </li></ul></ul></ul><ul><ul><ul><li>public MyClass(int index, String name) { } </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  11. 11. 快速入门 <ul><li>val 和 var (类型推断) </li></ul><ul><ul><li>不过 var a=null 和 java 不一样,不能再次赋值,因为这时已经被附成了 Null 类(强类型) </li></ul></ul><ul><li>def </li></ul><ul><li>Unit ,可认为是 void ,但不同 </li></ul><ul><li>Type less ,do more </li></ul><ul><ul><li>省略 ; </li></ul></ul><ul><ul><li>省略 return :但,递归函数必须显示声明返回类型 </li></ul></ul><ul><ul><li>省略 . </li></ul></ul><ul><ul><li>省略括号:注意的是 println 和 groovy 的不同 </li></ul></ul><ul><li>脚本语言? Ok ,可以当成脚本语言去写然后用 scala xx.scala 执行脚本 </li></ul><ul><li>数不存在 ++ , -- ,但可以自己定义 </li></ul><ul><li>任何东西都有返回值 </li></ul>
  12. 12. 快速入门 <ul><li>数组 Array </li></ul><ul><ul><li>不是用 [] 而是用 () </li></ul></ul><ul><ul><li>一个数组 Array[String] strs, 则 strs(1) 实际上是 strs.apply(1) </li></ul></ul><ul><ul><li>strs(1)= &quot;fsda&quot; 实际上是 strs.update(1, &quot;fsda&quot; ) </li></ul></ul><ul><ul><li>val numNames = Array( &quot;zero&quot; , &quot;one&quot; , &quot;two&quot; ) 实际上仍然是 Array.apply(&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;) ,但这里调用的是 Array 的伴随类的 apply </li></ul></ul><ul><ul><li>fill 、 tabulate 、 range (采用的是 until 策略) </li></ul></ul><ul><li>if 和 java 一样,必须是 boolean 而不像 groovy 那样 </li></ul><ul><li>不会强求你是否处理异常,但因为有个异常强大的模式匹配,异常处理也变得很华丽 </li></ul><ul><ul><li>catch { </li></ul></ul><ul><ul><li>case ex: FileNotFoundException => // Handle missing file </li></ul></ul><ul><ul><li>case ex: IOException => // Handle other I/O error </li></ul></ul><ul><ul><li>} </li></ul></ul>
  13. 13. 快速入门 <ul><li>更加简化的 foreach </li></ul><ul><ul><li>举个例子,循环一个数组并打印, java 传统写法 </li></ul></ul><ul><ul><li>for (int i:args) { </li></ul></ul><ul><ul><li>System.out.println(i); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>在 scala 中 </li></ul></ul><ul><ul><li>args.foreach(arg => println(arg)) </li></ul></ul><ul><ul><li>再简化 args.foreach(println(_)) </li></ul></ul><ul><ul><li>再简化 args.foreach(println) </li></ul></ul><ul><ul><li>再简化 args foreach println </li></ul></ul><ul><ul><li>java:38 个字, scala : 18 个字 </li></ul></ul>
  14. 14. 快速入门 <ul><li>函数文法 : 形如 (x: Int, y: Int) => x + y </li></ul><ul><li>for 的使用 </li></ul><ul><ul><li>for (arg <- 0 to 10) println(arg) </li></ul></ul><ul><ul><li>没有 for(int i=0;i<10;i++) </li></ul></ul><ul><ul><li>而且 for 中的东西都是 val 的 </li></ul></ul><ul><ul><li>PS : to ,这里是 Range ,不包含右界则是 until </li></ul></ul><ul><ul><li>range 用 by 定义 step:(10 until 0) by -1 </li></ul></ul><ul><li>List </li></ul><ul><ul><li>::: 组装两个 list 中的元素 </li></ul></ul><ul><ul><li>:: 加入到 list ,只容许 el::list, 反过来不行 </li></ul></ul><ul><ul><li>Nil 为空,相当于 List() </li></ul></ul><ul><ul><li>l(0)=3 是不可以的,因为没有 update , scala 中 List 是不可变的 </li></ul></ul>
  15. 15. 快速入门 <ul><li>Tuple </li></ul><ul><li>从 1 开始 </li></ul><ul><li>对于一些简单对象就没必要再弄 class 了,直接返回 tuple </li></ul><ul><li>val pair = (99, &quot;Luftballons&quot; ) </li></ul><ul><li>println(pair._1) </li></ul><ul><li>println(pair._2) </li></ul><ul><li>Set 、 Map </li></ul><ul><li>map(1-> &quot;fsda&quot; ) </li></ul><ul><li>读取文件 </li></ul><ul><li>import scala.io.Source </li></ul><ul><li>for (line <- Source.fromFile(args).getLines()) </li></ul><ul><li>println(line.length +&quot; &quot;+ line) </li></ul>
  16. 16. 快速入门 <ul><li>没有了 switch , scala 变得异常强大,采用了模式匹配方式,缺省用下划线 _ 表示所有 </li></ul><ul><li>xxx match { </li></ul><ul><li> case &quot;fsd&quot;:XXX </li></ul><ul><li> case _:YYY </li></ul><ul><li>} </li></ul><ul><li>xxx 可以是任何东西,所有的 break 已经隐含了,准确的说是根本没有 break </li></ul><ul><li>语法级别里没有 break 和 continue ,绝对没有,任何跳出请加判断,因为 break 之类的可以定义成方法,现在是在 util.control 里实现了 break 的 trait 和 object ( breakable{} ) </li></ul><ul><li>变量范围和 java 一样,但是,在嵌套范围内可以定义同外部一样的同名变量 </li></ul><ul><li>readLine 、 readBoolean 、 readByte 、 readShort 、 readChar 、 readInt 、 readLong 、 readFloat 、 readDouble 、 readf 等等, Console 下 </li></ul>
  17. 17. 快速入门 <ul><li>Option 类型( Option type ) , 可选类型,返回不确定类型的时候 </li></ul><ul><ul><li>非常常用 </li></ul></ul><ul><ul><li>有两种形式: 1.Some(x),x 就是实际值; 2.None </li></ul></ul><ul><ul><li>例子 </li></ul></ul><ul><ul><li>val capitals =Map( &quot;France&quot; -> &quot;Paris&quot; , &quot;Japan&quot; -> &quot;Tokyo&quot; ) </li></ul></ul><ul><ul><li>scala> capitals get &quot;France&quot; </li></ul></ul><ul><ul><li>res23: Option[java.lang.String] = Some(Paris) </li></ul></ul><ul><ul><li>scala> capitals get &quot;North Pole&quot; </li></ul></ul><ul><ul><li>res24: Option[java.lang.String] = None </li></ul></ul><ul><ul><li>所以这时可以用模式匹配 </li></ul></ul><ul><ul><li>def show(x: Option[String]) = x match { </li></ul></ul><ul><ul><li>case Some(s) => s </li></ul></ul><ul><ul><li>case None => &quot;?&quot; </li></ul></ul><ul><ul><li>} </li></ul></ul>
  18. 18. 快速入门 <ul><li>保留字 </li></ul><ul><li>abstract case catch class def do else extends false final finally for if implicit import match new null object override package private protected requires return sealed super this throw trait try true type val var while with yield </li></ul><ul><li>对比 java </li></ul><ul><li>abstract break boolean byte case catch char class continue const default do double else extends false final finally float for goto if implements import int interface instanceof long native new null package private protected public return short static super switch synchronized this throw throws transient true try void volatile while </li></ul><ul><li>而 groovy </li></ul><ul><li>abstract, as, assert, boolean, break, byte, case, catch, char, class, const, continue, def, default, do, double, else, enum, extends, false, final, finally, float, for, goto, if, implements, import, in, instanceof, int, interface, long, native, new, null, package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, threadsafe, throw, throws, transient, true, try, void, volatile, while </li></ul>
  19. 19. 快速入门 <ul><li>尾递归( Tail Recursio ) </li></ul><ul><ul><li>尾递归就是从最后开始计算 , 每递归一次就算出相应的结 </li></ul></ul><ul><ul><li>果 , 也就是说 , 函数调用出现在调用者函数的尾部 , 因为是 </li></ul></ul><ul><ul><li>尾部 , 所以根本没有必要去保存任何局部变量 . </li></ul></ul><ul><ul><li>所有的 while 都可以改写成尾递归 </li></ul></ul><ul><ul><li>def whileLoop(condition: => Boolean)(command: => Unit) { </li></ul></ul><ul><ul><li>if (condition) { </li></ul></ul><ul><ul><li>command; whileLoop(condition)(command) </li></ul></ul><ul><ul><li>} else () </li></ul></ul><ul><ul><li>} </li></ul></ul>
  20. 20. 加点难度 <ul><li>类、对象、函数 </li></ul><ul><ul><li>默认都是 public , var 、 val 、 def 也是 public 的 </li></ul></ul><ul><ul><li>默认的参数只要不加 var 就是 val 的 </li></ul></ul><ul><ul><li>不带返回类型和 = 的 def 方法返回都是 Unit </li></ul></ul><ul><li>object : scala 没有 static ,但提供了 object 来满足这种需要 </li></ul><ul><ul><li>不可有参数 </li></ul></ul><ul><ul><li>单例对象: standalone object ,可认为是 final 类 </li></ul></ul><ul><ul><li>与 class 同名的叫做伴随对象( companion object )对应的类叫做伴随类,它可以与同名类互相访问对方的私有对象 </li></ul></ul><ul><ul><li>object 会生成一个 $ 的 class ,仍然用原名可访问,但伴随类必须用 Object$.MODULE$ </li></ul></ul><ul><li>Scala 程序 </li></ul><ul><ul><li>main 方法:在 object 中定义 main 方法即可 def main(args: Array[String]) </li></ul></ul><ul><ul><li>java 默认引入了 lang , scala 默认引入了 Predef 及一些其他有用的东西 </li></ul></ul><ul><ul><li>scala 不用在意文件名之类的,也可以往文件中放任何类或对象 </li></ul></ul><ul><ul><li>scalac ; scala 脚本; fsc ; scaladoc ; sbaz ; sbt </li></ul></ul><ul><ul><li>sbaz install scala-devel-docs </li></ul></ul><ul><ul><li>可以继承 Application (已 deprecate 了,用 App 代替,这两个都是 trait ) </li></ul></ul>
  21. 21. 加点难度 <ul><li>基础类型 </li></ul><ul><ul><li>类型 Byte , Short , Int , Long 和 Char 被称为整数类型: integral type 。整数类型加上 Float 和 Double 被称为数类型: numeric type 。 </li></ul></ul><ul><ul><li>一个独立的 Boolean </li></ul></ul><ul><ul><li>和 java 一一对应,但都有相应的 RichXXX 类型,而且均为 final 类 </li></ul></ul><ul><ul><li>String 也有 &quot;&quot;&quot; ,用 | 来表示一行的起始, stripMargin 方法就可以去掉前面的空格,如 </li></ul></ul><ul><ul><ul><li>println( &quot;&quot;&quot;|Welcome to Ultamix 3000. </li></ul></ul></ul><ul><ul><ul><li>|Type &quot;HELP&quot; for help.&quot;&quot;&quot; .stripMargin) </li></ul></ul></ul><ul><li>操作符(前中后缀,其实,应该认为没有操作符,全是方法) </li></ul><ul><ul><li>任一方法都是操作符,操作符也可以随意重载 </li></ul></ul><ul><ul><li>从左到右,有一个例外:任何以‘ :’ 字符结尾的方法由它的右手侧操作数调用,并传入左操作数 </li></ul></ul><ul><ul><li>unary_ 前缀操作符,实际上如: -2.0 // Scala invokes (2.0).unary_- </li></ul></ul><ul><ul><li>前缀可用的只有 +, -, !, and ~ </li></ul></ul><ul><ul><li>其他基本和 java 一样,但是 == 不一样,相当于 equals , eq 和 ne 方法是 java 的 == </li></ul></ul><ul><ul><li>任何包括保留字都可以用反引号当做操作符 `yield` </li></ul></ul><ul><ul><li>任何操作符都是方法调用 XX op YY 相当于 XX.op(YY) </li></ul></ul>
  22. 22. 加点难度 <ul><li>隐式转换 </li></ul><ul><ul><li>class Myint(i:Int){ </li></ul></ul><ul><ul><li>def ++()=i+1 </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>implicit def intToMyint(i:Int):Myint= new Myint(i) </li></ul></ul><ul><li>内建控制结构 </li></ul><ul><ul><li>if , while ( do-while ), for , try , match 和函数调用 </li></ul></ul><ul><ul><li>没有 1>2?5:6 </li></ul></ul><ul><ul><li>函数类语言一般没有循环类结构, while , for 之类的,因为他们不返回值,比如 (line = readLine()) != &quot;&quot; 将永远为真,因为前者返回 Unit 相当于 () ,这个就没法在循环中判断,一般通过递归等方法实现 , 但 scala 不是纯 FP ,所以有 </li></ul></ul>
  23. 23. 更进一步 之 for <ul><li>没有 for(int i=0;i<xxx.length;i++) ,但却比这强大 </li></ul><ul><li>简易数字循环的话 for (i <-(50 to 0) by -2) println(i) </li></ul><ul><li>打印文件: </li></ul><ul><li>for ( file<-(new java.io.File(&quot;.&quot;)).listFiles ) println(file) </li></ul><ul><li>可以附加过滤器,但超过一个过滤器的时候要加上分号 </li></ul><ul><ul><li>val filesHere = ( new java.io.File( &quot;.&quot; )).listFiles </li></ul></ul><ul><ul><li>for ( </li></ul></ul><ul><ul><li>file <- filesHere </li></ul></ul><ul><ul><li>if file.isFile; </li></ul></ul><ul><ul><li>if file.getName.endsWith( &quot;.scala&quot; ) </li></ul></ul><ul><ul><li>) println(file) </li></ul></ul><ul><ul><li>// 可以使用大括号代替小括号环绕发生器和过滤器。使用大括号的一个好处是你可以省略一些使用小括号必须加的分号 </li></ul></ul>
  24. 24. 更进一步 之 for <ul><li>容许内部迭代和 mid-stream (流间)变量绑定 </li></ul><ul><li>def grep(pattern: String) = </li></ul><ul><li>for { </li></ul><ul><li>file <- filesHere </li></ul><ul><li>if file.getName.endsWith( &quot;.scala&quot; ) </li></ul><ul><li>line <- fileLines(file) </li></ul><ul><li>trimmed = line.trim //if line.trim.matches(pattern) </li></ul><ul><li>if trimmed.matches(pattern) </li></ul><ul><li>} println(file + &quot;: &quot; + trimmed) </li></ul><ul><li>grep(&quot;.*gcd.*&quot;) </li></ul><ul><li>可以用 for 创建新的集合,用 yield </li></ul><ul><ul><li>def scalaFiles = // 返回的结果是 Array[File] </li></ul></ul><ul><ul><li>for { </li></ul></ul><ul><ul><li>file <- filesHere </li></ul></ul><ul><ul><li>if file.getName.endsWith( &quot;.scala&quot; ) </li></ul></ul><ul><ul><li>} yield file </li></ul></ul><ul><ul><li>具体语法是: for { 子句 } yield { 循环体 } </li></ul></ul>
  25. 25. 更进一步 之 函数和闭包 <ul><li>函数可以定义成方法: method ,某个对象的成员 </li></ul><ul><li>本地函数:即把函数定义在函数内部 </li></ul><ul><li>第一类函数: first-class function ,形如 XX=>YYY (生成的是类) </li></ul><ul><li>比如 val increase = (x: Int) => x + 1 // 等号右边就是第一类函数 </li></ul><ul><li>如果超过一行的话,用大括号包起来 </li></ul><ul><li>可以使用短格式或者占位符代替参数,比如 filter ( x=>x>1 )或者 filter(_>1) 或者 filter(1<) </li></ul><ul><li>甚至可以 val f = (_: Int) + (_: Int) //f(5, 10) 调用 </li></ul><ul><li>偏应用函数: partially applied function (我个人认为应该叫部分应用函数) </li></ul><ul><li>def sum(a: Int, b: Int, c: Int) = a + b + c </li></ul><ul><li>val a = sum _ //=sum 是不行的,这时是定义函数,不可以简略,只有下面 foreach 那种确定要传入的是函数的情况下才可以省略 </li></ul><ul><li>val b = sum(1, _: Int, 3) </li></ul>
  26. 26. 更进一步 之 函数和闭包 <ul><li>闭包 </li></ul><ul><li>闭包( Closure )是词法闭包( Lexical Closure )的简称,是引用了自由变量(未绑定)的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。最早实现闭包的程序语言是 Scheme 。 </li></ul><ul><li>举个例子: </li></ul><ul><li>(x: Int) => x + more </li></ul><ul><li>more 是个自由变量: free variable ,因为函数文本自身没有给出其含义 ; 相对的, x 变量是一个绑定变量: bound variable ,因为它在函数的上下文中有明确意义 </li></ul><ul><li>不带自由变量的函数文本,如 (x: Int) => x + 1 ,被称为封闭术语: closed term ,这里术语: term 指的是一小部分源代码 </li></ul><ul><li>而例子则是是开放术语: open term </li></ul><ul><li>如果要是用这个开放术语的例子,则要定义 more 是什么,比如初始化为 0 , 依照这个函数文本在运行时创建的函数值(对象)被称为闭包: closure 。 </li></ul>
  27. 27. 更进一步 之 函数和闭包 <ul><li>函数的参数 </li></ul><ul><ul><li>重复参数 ,用 * 来表示 </li></ul></ul><ul><ul><ul><li>def echo(args: String*) = for (arg <- args) println(arg) </li></ul></ul></ul><ul><ul><ul><li>实际组织形式是数组,但是直接调用是不行的 </li></ul></ul></ul><ul><ul><li>命名参数 </li></ul></ul><ul><ul><ul><li>def speed(distance: Float, time: Float): Float =distance / time </li></ul></ul></ul><ul><ul><ul><li>speed(time = 10, distance = 100) </li></ul></ul></ul><ul><ul><li>默认参数 </li></ul></ul><ul><ul><ul><li>def c(a:Int=6)={println(a)} </li></ul></ul></ul><ul><ul><li>传名参数 </li></ul></ul><ul><ul><li>by-name parameter 采用 :=> 方式,大部分会用于 boolean 的判断,不会再调用的时候执行而是直接引入被调用的地方 </li></ul></ul>
  28. 28. 更进一步 之 函数和闭包 <ul><li>高阶函数 :higher-order function </li></ul><ul><li>指把另一个函数作为参数或返回值的函数 </li></ul><ul><li>def filesMatching(query: String, </li></ul><ul><li>matcher: (String, String) => Boolean) = { </li></ul><ul><li>for (file <- filesHere; if matcher(file.getName, query)) </li></ul><ul><li>yield file </li></ul><ul><li>} </li></ul><ul><li>def filesEnding(query: String) = filesMatching(query, _.endsWith(_)) </li></ul><ul><li>def filesContaining(query: String) = filesMatching(query, _.contains(_)) </li></ul><ul><li>def filesRegex(query: String) = filesMatching(query, _.matches(_)) </li></ul><ul><li>scala 大规模使用了高阶函数,比如,我想从一个 list 中打印出所有的奇数,这点在下面详解 List 的时可看到 </li></ul><ul><li>def containsOdd(nums: List[Int]) = nums.exists(_ % 2 == 1) </li></ul>
  29. 29. 更进一步 之 函数和闭包 <ul><li>克里化: Currying ,又叫局部调用 </li></ul><ul><ul><li>是把接受多个参数的函数变换成接受一 </li></ul></ul><ul><ul><li>个单一参数(最初函数的第一个参数) </li></ul></ul><ul><ul><li>的函数,并且返回接受余下的参数而且 </li></ul></ul><ul><ul><li>返回结果的新函数的技术。 </li></ul></ul><ul><ul><li>例子: </li></ul></ul><ul><ul><li>def curriedSum(x: Int)(y: Int) = x + y </li></ul></ul><ul><ul><li>val onePlus = curriedSum(1)_ </li></ul></ul>Haskell Brooks Curry
  30. 30. 更进一步 之 类 <ul><li>仍然是 abstract 定义抽象类, extends 继承 </li></ul><ul><li>final 啥的也都在 </li></ul><ul><li>Scala 里禁止在同一个类里用同样的名称定义字段和方法 </li></ul><ul><li>参数化字段,又称为类参数 </li></ul><ul><ul><li>class ArrayElement( // 请注意,小括号 </li></ul></ul><ul><ul><li>val contents: Array[String] </li></ul></ul><ul><ul><li>) extends Element </li></ul></ul><ul><li>Scala 里所有重载了父类具体成员的成员都需要修饰符 override </li></ul>
  31. 31. 更进一步 之 类 <ul><li>scala 的继承树 </li></ul><ul><ul><li>所有都继承自 Any ,而 Null 和 Nothing 是所有的子类 </li></ul></ul><ul><ul><li>Any 有如下方法: </li></ul></ul><ul><ul><li>def != (arg0: Any): Boolean </li></ul></ul><ul><ul><li>def ## (): Int </li></ul></ul><ul><ul><li>def == (arg0: Any): Boolean </li></ul></ul><ul><ul><li>def asInstanceOf [T0] : T0 </li></ul></ul><ul><ul><li>def equals (arg0: Any): Boolean </li></ul></ul><ul><ul><li>def hashCode (): Int </li></ul></ul><ul><ul><li>def isInstanceOf [T0] : Boolean </li></ul></ul><ul><ul><li>def toString (): String </li></ul></ul>
  32. 32. 更进一步 之 类 <ul><li>根类 Any 有两个子类: AnyVal 和 AnyRef 。 AnyVal 是 Scala 里每个内建值类的父类。有九个这样的值类: Byte , Short , Char , Int , Long , Float , Double , Boolean 和 Unit 。其中的前八个对应到 Java 的原始类型,它们的值在运行时表示成 Java 的原始值。 Scala 里这些类的实例都写成文本。值类都被定义为既是抽象的又是 final 的 </li></ul><ul><li>类 Any 的另一个子类是类 AnyRef 。这个是 Scala 里所有引用类的基类 ,AnyRef 实际就是类 java.lang.Object 的别名。 Scala 类与 Java 类不同在于它们还继承自一个名为 ScalaObject 的特别的记号特质, ScalaObject 包含了 Scala 编译器定义和实现的方法,目的是让 Scala 程序的执行更有效 </li></ul>
  33. 33. 更进一步 之 类 <ul><li>另一个值类, Unit ,大约对应于 Java 的 void 类型;被用作不返回任何有用结果的方法的结果类型。 Unit 只有一个实例值,被写作 () </li></ul><ul><li>类 Null 是 null 类型的引用;它是每个引用类(就是说,每个继承自 AnyRef 的类)的子类。 Null 不兼容值类型。 </li></ul><ul><li>类型 Nothing 在 Scala 的类层级的最底端;它是任何其它类型的子类型。 Nothing 的一个用处是它标明了不正常的终止。 </li></ul>
  34. 34. 更进一步 之 类
  35. 35. 更进一步 之 特质 trait <ul><li>trait 是 Scala 里代码复用的基础单元。特质封装了方法和字段的定义,并可以通过混入到类中重用它们。不像类的继承那样,每个类都只能继承唯一的超类,类可以混入任意个特质。 </li></ul><ul><li>用 extends 或 with 混入( mix-in ) trait </li></ul><ul><li>特质就像是带有具体方法的 Java 接口。 </li></ul><ul><ul><li>第一点,特质不能有任何“类参数”,也就是说,传递给类的主构造器的参数 </li></ul></ul><ul><ul><li>第二点,不论在类的哪个角落, super 调用都是静态绑定的,在特质中,它们是动态绑定的 </li></ul></ul><ul><li>混入的次序非常重要 , 粗略地说,越靠近右侧的特质越先起作用 </li></ul>
  36. 36. 更进一步 之 特质 trait <ul><li>scala 线性继承算法: 1. 自己; 2. 从右边开始继承,并把每一个所继承的线性继承累计进入线性继承; 3. 从左往右看,把每一个右边已有的继承去掉重复的; 4. 加上 ScalaObject , AnyRef , Any </li></ul><ul><li>举个例子: </li></ul><ul><ul><li>class Human </li></ul></ul><ul><ul><li>trait Woman extends Human </li></ul></ul><ul><ul><li>trait Driver extends Human </li></ul></ul><ul><ul><li>trait FemaleDriver extends Driver </li></ul></ul><ul><ul><li>trait MarriedWoman extends Woman </li></ul></ul><ul><ul><li>trait SixFingers extends Human </li></ul></ul><ul><ul><li>class MarriedSixFingersFemaleDriver extends MarriedWoman with FemaleDriver with SixFingers </li></ul></ul><ul><ul><li>最终的结果就是 SF FD D MW W H ( SO AR A ) </li></ul></ul>
  37. 37. 更进一步 之 包、引用、断言 <ul><li>包机制,和 java 一样,但可以用类似命名空间那样的 package xx{} 继续定义 </li></ul><ul><li>引用 </li></ul><ul><li>仍然是 import ,但这里不用 * 而是用占位符 _ 表示整个包下所有东西,也可以引入类的所有东西(成员或方法) </li></ul><ul><li>可以随时 import </li></ul><ul><li>可以选择引用,或改名引用 import Fruits.{Apple , Orange} , import java.{sql => S} , import java.sql.{Date => SDate} , import Fruits.{Apple => McIntosh, _} </li></ul><ul><li>特例: import Fruits.{Pear => _, _} </li></ul><ul><li>这个引用了除 Pear 之外的所有 Fruits 成员 </li></ul><ul><li>总结就是 : </li></ul><ul><li>1. 简单名 x 。把 x 包含进引用名集。 </li></ul><ul><li>2. 重命名子句 x => y 。让名为 x 的成员以名称 y 出现。 </li></ul><ul><li>3. 隐藏子句 x => _ 。把 x 排除在引用名集之外。 </li></ul><ul><li>全包括‘ _’ 。引用除了前面子句提到的之外的全体成员。如果存在全包括,那么必须是引用选择的最后一个。 </li></ul>
  38. 38. 更进一步 之 包、引用、断言 <ul><li>默认引用 </li></ul><ul><li>import java.lang._ // java.lang 包的所有东西 </li></ul><ul><li>import scala._ // scala 包的所有东西 </li></ul><ul><li>import Predef._ // Predef 对象的所有东西 </li></ul><ul><li>Predef 是个非常牛的东西,需要单用一节课去讲 </li></ul><ul><li>留个作业:如果真的想学 scala 的话,把 Predef 看了 </li></ul><ul><li>可见范围 </li></ul><ul><li>所有默认都是 public , private 和 protected 仍然存在。当定义了 private [bobsrockets] 。这就是说这个类对包含在 bobsrockets 包的所有的类和对象可见 </li></ul><ul><li>类把它所有的访问权限共享给伴生对象,反过来也是如此。 </li></ul><ul><li>包对象 </li></ul><ul><li>每个包都可以有一个包对象( package object ),把所有包级别共同的可以定义在内, 2.8 加入 </li></ul><ul><li>断言 </li></ul><ul><li>assert , assume , require </li></ul>
  39. 39. 更进一步 之 case 类和模式匹配 <ul><li>case 类( Case Classes ) </li></ul><ul><li>Case 类用 case 关键词修饰 </li></ul><ul><ul><ul><li>1. 会在编译时加入一个工厂方法,不用再 new 出来,可以直接生成。 </li></ul></ul></ul><ul><ul><ul><li>2. 所有的类参数会加上 val ,也就是自动转变成 field ; </li></ul></ul></ul><ul><ul><ul><li>3. 加入一些自然实现的方法 toString,hashCode, and equals ; </li></ul></ul></ul><ul><ul><ul><li>4. 自动加入了一个 copy 方法 </li></ul></ul></ul><ul><li>模式匹配( Pattern Matching ): selector match { alternatives } </li></ul><ul><li>而 alternatives 都是从 case 开始,一个模式和一或多个表达式去判断模式是否匹配,还有一个 => </li></ul><ul><li>所有 break 都是隐含的(而且没有 break 这个东西) </li></ul>
  40. 40. 更进一步 之 模式匹配 <ul><li>通配符匹配 </li></ul><ul><ul><li>_ 可以通配所有,类似 default ,但是在 pattern 中出现的话就是通配中间的东西了 </li></ul></ul><ul><li>常量匹配、变量匹配(正则 Regex() 或者 .r ) </li></ul><ul><ul><li>scala> import math.{E, Pi} </li></ul></ul><ul><ul><li>import math.{E, Pi} </li></ul></ul><ul><ul><li>scala> val pi = math.Pi </li></ul></ul><ul><ul><li>pi: Double = 3.141592653589793 </li></ul></ul><ul><ul><li>scala> E match { </li></ul></ul><ul><ul><li>| case `pi` => &quot;strange math? Pi = &quot;+ pi </li></ul></ul><ul><ul><li>| case _ => &quot;OK&quot; </li></ul></ul><ul><ul><li>| } </li></ul></ul><ul><ul><li>res0: java.lang.String = OK </li></ul></ul><ul><ul><li>scala> Pi match { </li></ul></ul><ul><ul><li>| case `pi` => &quot;strange math? Pi = &quot;+ pi </li></ul></ul><ul><ul><li>| case _ => &quot;OK&quot; </li></ul></ul><ul><ul><li>| } </li></ul></ul><ul><ul><li>res1: java.lang.String = strange math? Pi = 3.141592653589793 </li></ul></ul><ul><ul><li>val Dpi = math.Pi </li></ul></ul><ul><ul><li>Pi match { </li></ul></ul><ul><ul><li>case Dpi => &quot;strange math? Pi = &quot;+ pi </li></ul></ul><ul><ul><li>case _ => &quot;OK&quot; </li></ul></ul><ul><ul><li>} </li></ul></ul>
  41. 41. 更进一步 之 模式匹配 <ul><li>构造器匹配、序列化匹配 </li></ul><ul><ul><li>expr match { </li></ul></ul><ul><ul><li>case List(0, _, _) => println(&quot;found it&quot;) </li></ul></ul><ul><ul><li>//case List(0, _*) => println(&quot;found it&quot;) </li></ul></ul><ul><ul><li>case _ => </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>tuple 匹配 </li></ul><ul><li>expr match { </li></ul><ul><li>case (a, b, c) => println(&quot;matched &quot;+ a + b + c) </li></ul><ul><li>case _ => </li></ul><ul><li>} </li></ul><ul><li>类型匹配 </li></ul><ul><li>x match { </li></ul><ul><li>case s: String => s.length </li></ul><ul><li>case m: Map[_, _] => m.size </li></ul><ul><li>case _ => -1 </li></ul><ul><li>} </li></ul><ul><li> 注意的是,类型是消除的,不能用泛型匹配,比如 case m: Map[Int, Int] => true ,但唯一例外的是 Array ,可以泛型匹配 </li></ul>
  42. 42. 更进一步 之 模式匹配 <ul><li>变量绑定 </li></ul><ul><li>expr match { </li></ul><ul><li>case UnOp(&quot;abs&quot;, e @ UnOp(&quot;abs&quot;, _)) => e </li></ul><ul><li>case _ => </li></ul><ul><li>} </li></ul><ul><li>模式保护 </li></ul><ul><li>e match { </li></ul><ul><li>case BinOp(&quot;+&quot;, x, x) => BinOp(&quot;*&quot;, x, Number(2)) </li></ul><ul><li>case _ => e </li></ul><ul><li>} // 编译不过,因为出现了两个 x ,而 scala 的模式要求是线性模式 </li></ul><ul><li>def simplifyAdd(e: Expr) = e match { </li></ul><ul><li>case BinOp(&quot;+&quot;, x, y) if x == y =>BinOp(&quot;*&quot;, x, Number(2)) </li></ul><ul><li>case _ => e </li></ul><ul><li>} </li></ul><ul><li>模式保护就是指在模式后以 if 开头的 boolean 表达式 </li></ul>
  43. 43. 更进一步 之 封闭类 <ul><li>封闭类( Sealed classes )非封闭类在 match 可用 @unchecked 取消 warning </li></ul>sealed abstract class HttpMethod() case class Connect(body: String) extends HttpMethod case class Delete (body: String) extends HttpMethod case class Get (body: String) extends HttpMethod case class Head (body: String) extends HttpMethod case class Options(body: String) extends HttpMethod case class Post (body: String) extends HttpMethod case class Put (body: String) extends HttpMethod case class Trace (body: String) extends HttpMethod def handle (method: HttpMethod) = method match { case Connect (body) => println(&quot;connect: &quot; + body) case Delete (body) => println(&quot;delete: &quot; + body) case Get (body) => println(&quot;get: &quot; + body) case Head (body) => println(&quot;head: &quot; + body) case Options (body) => println(&quot;options: &quot; + body) case Post (body) => println(&quot;post: &quot; + body) case Put (body) => println(&quot;put: &quot; + body) case Trace (body) => println(&quot;trace: &quot; + body) }
  44. 44. 更进一步 之 模式匹配的例子 <ul><li>scala> val myTuple = (123, &quot;abc&quot;) </li></ul><ul><li>myTuple: (Int, java.lang.String) = (123,abc) </li></ul><ul><li>scala> val (number, string) = myTuple </li></ul><ul><li>number: Int = 123 </li></ul><ul><li>string: java.lang.String = abc </li></ul>
  45. 45. 更进一步 之 模式匹配的例子 <ul><li>scala> val exp = new BinOp(&quot;*&quot;, Number(5), Number(1)) </li></ul><ul><li>exp: BinOp = BinOp(*,Number(5.0),Number(1.0)) </li></ul><ul><li>scala> val BinOp(op, left, right) = exp </li></ul><ul><li>op: String = * </li></ul><ul><li>left: Expr = Number(5.0) </li></ul><ul><li>right: Expr = Number(1.0) </li></ul><ul><li>for 也是有模式匹配的 </li></ul><ul><li>for ((country, city) <- capitals) </li></ul><ul><li>println( &quot;The capital of &quot; + country + &quot; is &quot; + city) </li></ul>
  46. 46. 更进一步 之 模式匹配的例子 <ul><li>scala> val results = List(Some(&quot;apple&quot;), None,Some(&quot;orange&quot;)) </li></ul><ul><li>results: List[Option[java.lang.String]] = List(Some(apple),None, Some(orange)) </li></ul><ul><li>scala> for (Some(fruit) <- results)println(fruit) </li></ul><ul><li>apple </li></ul><ul><li>orange </li></ul>
  47. 47. 更进一步 之 List <ul><li>和 Array 类似,但是: 1.List 不可变; 2.List 是递归的, Array 是平的 </li></ul><ul><ul><li>1.List 是同质的( homogeneous ),即 List 中的东西都是同类的 </li></ul></ul><ul><ul><li>2.List 是协变的( covariant ),举例: S 是 T 的子类,那么 List[S] 是 </li></ul></ul><ul><ul><li>List[T] 的子类 </li></ul></ul><ul><ul><li>List() 是 List[Nothing] </li></ul></ul><ul><ul><li>构造 List : List 有两个东西构成: 1. Nil ,为空 list ; 2.:: ( cons ),中 </li></ul></ul><ul><ul><li>缀符,连接了元素(前面)和 list (后面) </li></ul></ul><ul><ul><li>注意这三个是类, List 本身是 +T 的 abstract 类,有一个伴随类以用于 </li></ul></ul><ul><ul><li>初始化 </li></ul></ul><ul><ul><li>Nil 继承自 List[Nothing] ,由于是协变的,所以适用于所有 List 对象 </li></ul></ul><ul><ul><li>List(1, 2, 3) // 1 :: (2 :: (3 :: Nil))//1::2::3::Nil </li></ul></ul><ul><ul><li>//1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3) </li></ul></ul>
  48. 48. 更进一步 之 List <ul><li>所有的对 List 的操作都可以定义到下面的三个: </li></ul><ul><ul><li>1.isEmpty :是否为空 </li></ul></ul><ul><ul><li>2.head : list 中的第一个元素 </li></ul></ul><ul><ul><li>3.tail : list 除了第一个剩下的元素 </li></ul></ul><ul><ul><li>这三个方法在 List 中是 abstract 的,被 Nil 和 :: 定义 </li></ul></ul><ul><li>:: </li></ul><ul><li>在模式匹配时,操作符的定义不同, x::xs 是一个特殊中缀操作模式,并不是 x.::(xs) ,而是 ::(x,xs) // 下面的例子是插入排序 </li></ul><ul><li>留作业自己看吧 </li></ul><ul><li> def isort(xs: List[Int]): List[Int] = xs match { </li></ul><ul><ul><li>case List() => List() </li></ul></ul><ul><ul><li>case x :: xs1 => insert(x, isort(xs1)) </li></ul></ul><ul><li>} </li></ul><ul><li>def insert(x: Int, xs: List[Int]): List[Int] = xs match { </li></ul><ul><ul><li>case List() => List(x) </li></ul></ul><ul><ul><li>case y :: ys => if (x <= y) x :: xs else y :: insert(x, ys) </li></ul></ul><ul><li>} </li></ul>
  49. 49. 更进一步 之 List <ul><li>::: 也是右联合的,和 :: 一样,组合 list 内的元素为新 list </li></ul><ul><li>实现同样的功能 </li></ul><ul><li>def append[T](xs: List[T], ys: List[T]): List[T] =xs match { </li></ul><ul><li>case List() => ys </li></ul><ul><li>case x :: xs1 => x :: append(xs1, ys) </li></ul><ul><li>} </li></ul><ul><li>length </li></ul><ul><li>xs length// 返回长度,而不是 size(), 由于 list 是递归的,所以用这个方法需要谨慎,因为它的定义 </li></ul><ul><li>var these = self </li></ul><ul><li>var len = 0 </li></ul><ul><li>while (!these.isEmpty) { </li></ul><ul><li>len += 1 </li></ul><ul><li>these = these.tail </li></ul><ul><li>} </li></ul><ul><li>len </li></ul><ul><li>也就是说,为了得到长度需要遍历整个 list ,和 LinkedList 不一样, LinkedList 在 </li></ul><ul><li>内部有个 size 域 </li></ul>
  50. 50. 更进一步 之 List <ul><li>init :除了最后一个以外的 list </li></ul><ul><li>last :最后一个,都不能对 () 使用 </li></ul><ul><ul><li>------------------- 这两个也要遍历整个 list------------------- </li></ul></ul><ul><li>reverse :反转,同时,也是自反的 </li></ul><ul><ul><li>xs.reverse.reverse equals xs </li></ul></ul><ul><li>drop :扔掉前 n 个 , take :得到前 n 个 , splitAt :从 n 处砍成两个 list ,当 n 大于长度时,第一个返回 () ,第二个全部 </li></ul><ul><ul><li>xs splitAt n 相当于 (xs take n, xs drop n) </li></ul></ul><ul><li>选择 list 中的元素通过 apply ,也就是 xs(1) 实际上是 xs.apply(1) ,还可以写成 xs apply 1, 复杂度是 n ,所以 list 很适合随机取 </li></ul><ul><li>indices 可以返回元素的序号,返回的是 Range 类型 </li></ul>
  51. 51. 更进一步 之 List <ul><li>flatten :扁平化多个 list 成一个,只对 list 本身也是由 list 组成的 list 管用 </li></ul><ul><li>scala> List(List(1, 2), List(3), List(), List(4, 5)).flatten </li></ul><ul><li>res14: List[Int] = List(1, 2, 3, 4, 5) </li></ul><ul><li>zip :将两个 list 组成配对的 list (一般这个配对就是指 Tuple ) </li></ul><ul><li>scala> val xs=List(1,2,3);val xs1=List('a','b','n') </li></ul><ul><li>xs: List[Int] = List(1, 2, 3) </li></ul><ul><li>xs1: List[Char] = List(a, b, n) </li></ul><ul><li>scala>val xs2= xs zip xs1 </li></ul><ul><li>xs2: List[(Int, Char)] = List((1,a), (2,b), (3,n)) zipWithIndex :用序号组合 </li></ul><ul><li>scala> xs1 zipWithIndex </li></ul><ul><li>res6: List[(Char, Int)] = List((a,0), (b,1), (n,2)) </li></ul>
  52. 52. 更进一步 之 List <ul><li>unzip : zip 的反例 </li></ul><ul><ul><li>scala> xs2 unzip </li></ul></ul><ul><ul><li>res6: (List[Int], List[Char]) = (List(1, 2, 3),List(a, b, n)) </li></ul></ul><ul><li>toString : </li></ul><ul><ul><li>scala> xs2 toString </li></ul></ul><ul><ul><li>res12: String = List((1,d), (2,fsd), (das,fsda)) </li></ul></ul><ul><li>mkString :组装成需要的 String ,一种是提供三个参数,一种是不提供或一个参数 </li></ul><ul><ul><li>scala> xs2 mkString &quot; and &quot; </li></ul></ul><ul><ul><li>res14: String = (1,d) and (2,fsd) and (das,fsda) </li></ul></ul><ul><ul><li>scala> xs2.mkString(&quot;a list:&quot;,&quot;,&quot;,&quot; end&quot;) </li></ul></ul><ul><ul><li>res15: String = a list:(1,d),(2,fsd),(das,fsda) end </li></ul></ul>
  53. 53. 更进一步 之 List <ul><li>sum 、 product 、 min 、 max </li></ul><ul><li>iterator, toArray, copyToArray (当然 Array 也有 toList ) </li></ul><ul><li>xs copyToArray (arr, start) ,把 xs 拷到 arr 从 start 开始的位置,覆盖, arr 是不动的 </li></ul>
  54. 54. 更进一步 之 List 高阶方法 <ul><li>map : xs map f ,表示着返回一个有 xs 里的每个元素执行一遍 f 的结果的 list </li></ul><ul><ul><li>val xs=List(&quot;fsdaFsdaFsdaFdsa&quot;,&quot;gfdh&quot;,&quot;fFDS&quot;) </li></ul></ul><ul><ul><li>scala> xs map (_.length) </li></ul></ul><ul><ul><li>res25: List[Int] = List(16, 4, 4) </li></ul></ul><ul><ul><li>for (x <- expr1) yield expr2 就相当于 expr1.map(x => expr2) </li></ul></ul><ul><li>flatMap :对 list 中的 list 的每个元素进行操作 </li></ul><ul><ul><li>scala> xs map (_.toList) </li></ul></ul><ul><ul><li>res26: List[List[Char]] = List(List(f, s, d, a, F, s, d, a, F, s, d, a, F, d, s, a), List(g, f, d, h), List(f, F, D, S)) </li></ul></ul><ul><ul><li>scala> xs flatMap (_.toList) </li></ul></ul><ul><ul><li>res27: List[Char] = List(f, s, d, a, F, s, d, a, F, s, d, a, F, d, s, a, g, f, d, h, f, F, D, S) </li></ul></ul>
  55. 55. 更进一步 之 List 高阶方法 <ul><li>foreach </li></ul><ul><ul><li>每一个进行 f ,返回最终结果永远是 Unit ,也就是说,这里的 f 是一个过程计算,不返回东西 </li></ul></ul><ul><ul><li>scala> var sum=0;List.range(1,5) foreach (sum+=_) </li></ul></ul><ul><ul><li>sum: Int = 10 </li></ul></ul><ul><li>filter :过滤 </li></ul><ul><ul><li>scala> List.range(1,10) filter (_ %2==1) </li></ul></ul><ul><ul><li>res34: List[Int] = List(1, 3, 5, 7, 9) </li></ul></ul><ul><li>partition :和 filter 相似,但会返回两个 list 组成的 pair ,前面是符合的,后面是不符合的 </li></ul><ul><ul><li>scala> List.range(1,10) partition (_ %2==1) </li></ul></ul><ul><ul><li>res36: (List[Int], List[Int]) = (List(1, 3, 5, 7, 9),List(2, 4, 6, 8)) </li></ul></ul>
  56. 56. 更进一步 之 List 高阶方法 <ul><li>find :只返回第一个对的,没有则返回 None ,也就是说返回是可选类型值( optional value ) </li></ul><ul><ul><li>scala> List.range(1,10) find (_ %2==1) </li></ul></ul><ul><ul><li>res37: Option[Int] = Some(1) </li></ul></ul><ul><li>takeWhile 、 dropWhile :得到前面最多个符合的 list ;去掉前面最多个符合的 list </li></ul><ul><ul><li>scala> List.range(1,10) takeWhile (_ <3) // 如果第一个就不符合的话返回 () </li></ul></ul><ul><ul><li>res43: List[Int] = List(1, 2) </li></ul></ul><ul><ul><li>scala> List.range(1,10) dropWhile (_ <3) // 从前往后第一个不符合就返回全部 </li></ul></ul><ul><ul><li>res45: List[Int] = List(3, 4, 5, 6, 7, 8, 9) </li></ul></ul><ul><li>span :上两个组合 </li></ul><ul><ul><li>相当于 xs span p equals (xs takeWhile p, xs dropWhile p) </li></ul></ul>
  57. 57. 更进一步 之 List 高阶方法 <ul><li>forall :返回所有的是否都满足 f </li></ul><ul><li>exists :存在有满足 f 的 </li></ul><ul><li>sortWith :排序,根据传入的 f 进行排序,比如按照字段长度什么的 </li></ul><ul><li>Folding lists: /: and :</li></ul><ul><li>list 提供了两个方法 sum 和 product ,在上面已经提到过,那么,用左联定的话: </li></ul><ul><li>sum 的定义 def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus) </li></ul><ul><li>product 的定义 def product[B >: A](implicit num: Numeric[B]): B = foldLeft(num.one)(num.times) </li></ul><ul><li>这里用到的就是左联, foldLeft ,也就是 /: </li></ul><ul><li>自己实现的话就是 </li></ul><ul><li>(0 /: xs) (_ + _) </li></ul><ul><li> (1 /: xs) (_ * _) </li></ul>
  58. 58. 更进一步 之 List 左右联 <ul><li>左联( fold left )操作: (z /: xs) (op) 有三个组成部分, z :初始值; xs :要参与操作的 list ; op :二元操作 </li></ul><ul><li>例子: (z /: List(a, b, c)) (op) 就是 op(op(op(z, a), b), c) </li></ul><ul><li>用图来讲就是左倾树 </li></ul><ul><li>举个例子,我想设计一个方法,传入一个 list ,一个默认值,算出总和,那么 </li></ul><ul><li>scala> def sum(defaultValue:Int,xs:List[Int]):Int=(defaultValue /: xs) (_+_) </li></ul><ul><li>那么 :就是右联,右倾树 </li></ul><ul><li>(List(a, b, c) :z) (op) equals op(a, op(b, op(c, z))) </li></ul><ul><li>留个作业:如何用左联实现 reverse </li></ul>
  59. 59. 更进一步 之 List 高阶方法 <ul><li>list 的伴随类 object </li></ul><ul><ul><li>a) List.apply :其实上边已经用了很多了,就是 List(1,2,3) 这个就是 apply 出来的 </li></ul></ul><ul><ul><li>b) List.range(from, until) :上边也用过了 </li></ul></ul><ul><ul><li>c) List.fill :这是一个 curry 函数,生成若干维度若干个的同样填充元素的 list </li></ul></ul><ul><ul><li>d) List.tabulate :和上边一样,只不过第二个参数传的是 f ,返回的也是 f 后的 list </li></ul></ul><ul><ul><li>e) List.concat :将若干个 list 组成一个 </li></ul></ul><ul><li>List 有个问题,它只在处理 head::tail 很好,但如果你想在后边 append 的话就郁闷了,这时候就要用 ListBuffer ,这是一个可改变的集合, xs += el 用来 append , el +=: xs 用于从前面添加,复杂度 1 ,然后用 toList 可以得到 list (同样, ArrayBuffer 提供了可以删除头或尾的方法) </li></ul><ul><li>Stream ,和 List 一样,用 cons 代替 :: ,用 append 代替 ::: ,比如要算出 50000 以下第 17 个可以被 17 整除的是谁 , 我可以直接写 List.range(50000,49500,-1).filter(_ % 17 ==0)(16) 但 ... </li></ul>
  60. 60. 更进一步 之 StringOps 和 Tuple <ul><li>由于 Predef 提供了 String 到 StringOps 的隐式转换,于是就有了很多东西, StringOps 是集合类的 </li></ul><ul><li>&quot;fsdfsdfsdfsdFsd&quot;.exists(_.isUpper) </li></ul><ul><li>Tuple ,也是集合类,投连险状态也用可以用这个来解决 </li></ul>
  61. 61. 更进一步 之 Set 和 Map <ul><li>Set 和 Map ,都有可变不可变两种,默认不可变 </li></ul><ul><li>Set 提供了 + 、 - 、 ++ 、 -- 、 & 等等常用方法 </li></ul><ul><li>Map 有三种赋值方式,一种是 map(1)=&quot;a&quot;, 一种是 map(1->&quot;a&quot;) , map += 1 -> &quot;a&quot; </li></ul><ul><li>同样也有那些方法,然后多了 keys 、 keySet 、 values 等自有的方法 </li></ul><ul><li>最有意思的就是,会根据你的元素数量决定用什么, Map 同理(这点应该说是为 </li></ul><ul><li>了性能的极致,可参见 Tuple 、 Function 、 Product 等,定义了 20 余个) </li></ul><ul><li>元素数量 用 </li></ul><ul><li>0 scala.collection.immutable.EmptySet </li></ul><ul><li>1 scala.collection.immutable.Set1 </li></ul><ul><li>2 scala.collection.immutable.Set2 </li></ul><ul><li>3 scala.collection.immutable.Set3 </li></ul><ul><li>4 scala.collection.immutable.Set4 </li></ul><ul><li>5 or more scala.collection.immutable.HashSet </li></ul><ul><li>同样也有 TreeMap 和 TreeSet ,排序的集合 </li></ul><ul><li>Set(1, 2, 3) == Set(3, 2, 1) //List 为 false </li></ul><ul><li>Set 的 +- 只能对单一数据,对 Set 操作用 ++ 、 -- 、 ** (返回共同数据) </li></ul>
  62. 62. 更进一步 之 类型参数化 <ul><li>类型参数化( Type Parameterization ) </li></ul><ul><li>类成员 (type member): 用标识 type 声明 </li></ul><ul><li>在 scala 中泛型默认是非变的( nonvariant )或者说严格的( rigid )子类型 </li></ul><ul><li>在定义时泛型加入 + 标志着子类型是协变( covariant )的,与之对应的 - 标志 </li></ul><ul><li>着子类型是逆变( contravariant )的 </li></ul><ul><li>类型是协变、逆变还是非变的,被称为参数的变化( variance ), + 、 - 被称 </li></ul><ul><li>为变化注解 </li></ul><ul><li>U >: T </li></ul><ul><li>这是类型下界 (lower bound) 的定义,也就是 U 必须是类型 T 的父类 ( 或本身, </li></ul><ul><li>自己也可以认为是自己的父类 ) 。 </li></ul><ul><li>S <: T </li></ul><ul><li>这是类型上界( upper bound )的定义,也就是 S 必须是类型 T 的子类(或本 </li></ul><ul><li>身,自己也可以认为是自己的子类 ) 。 </li></ul><ul><li>这里隐含了一个 type ,也就是类成员定义 </li></ul>
  63. 63. 更进一步 之 类型参数化 <ul><li>lazy 变量,在 val 第一次被使用的时候才会被初始化,举个反例 </li></ul><ul><li>scala> object Demo {val x = { println(&quot;initializing x&quot;); &quot;done&quot; }} </li></ul><ul><li>scala> Demo </li></ul><ul><li>initializing x </li></ul><ul><li>res3: Demo.type = Demo$@17469af </li></ul><ul><li>scala> Demo.x </li></ul><ul><li>res4: java.lang.String = done </li></ul><ul><li>结构子类型(鸭子类型 Duck-typing ) </li></ul><ul><li>举个例子,我需要一个通用的打印后关闭,流、文件都行 </li></ul><ul><li>def using[T <: { def close(): Unit }, S](obj: T)(operation: T => S) = { </li></ul><ul><ul><li>val result = operation(obj) </li></ul></ul><ul><ul><li>obj.close() </li></ul></ul><ul><ul><li>result </li></ul></ul><ul><li>} </li></ul>
  64. 64. 更进一步 之 隐式转换 <ul><li>隐式转换( Implicit Conversions ) </li></ul><ul><li>用 implicit 实现,当编译器看到一个 X ,而这时应该需要的是 </li></ul><ul><li>Y ,那么编译器就去找隐式转换方法 </li></ul><ul><li>implicit def xtoy(x:X):Y={bulabula... // 实现 x 到 Y 类型的转化 } </li></ul><ul><li>留个作业,回去看 -> ,这个实际上是 ArrowAssoc 类,定义在 </li></ul><ul><li>Predef 里,看看在 map 定义的时候 -> 返回的到底是什么 </li></ul><ul><li>implicit 不只可以隐式转换类,还可以出现在参数里,变成隐 </li></ul><ul><li>式参数 </li></ul><ul><li>视界 view bound </li></ul><ul><li>S <% T ,与 <: 类似,但是要求 S 可以当成右边的 T 来对待, </li></ul><ul><li>并不是说 S 是 T 的子类,而可以对待就是指 S 可以转换为 T </li></ul><ul><li>scala -Xprint:typer </li></ul>
  65. 65. 更进一步 之 apply 和 unapply <ul><li>apply 组装器 </li></ul><ul><li>unapply 提取器 </li></ul><ul><li>object EMail { </li></ul><ul><li>def apply(user: String, domain: String) = user + &quot;@&quot; + domain </li></ul><ul><li>def unapply(str: String): Option[(String, String)] = { </li></ul><ul><li>val parts = str split &quot;@&quot; </li></ul><ul><li>if (parts.length == 2) Some(parts(0), parts(1)) else None </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  66. 66. 更进一步 之 Annotation <ul><li>@scala.reflect.BeanProperty </li></ul><ul><li>@serializable </li></ul><ul><li>@deprecated </li></ul><ul><li>@volatile </li></ul><ul><li>@tailrec </li></ul><ul><li>@unchecked </li></ul><ul><li>@native </li></ul><ul><li>@getter </li></ul><ul><li>@setter </li></ul>
  67. 67. 更进一步 之 XML <ul><li>XML :原生语言支持,直写就可以, XML 对象对应是 scala.xml.Elem </li></ul><ul><ul><li><a>hello world</a> </li></ul></ul><ul><ul><li>// 当中间的内容需要运算得出时,用花括号括起来 </li></ul></ul><ul><ul><li><a> { &quot;hello&quot; + &quot;, world&quot; } </a> </li></ul></ul><ul><ul><li>//text 方法可返回中间的内容 </li></ul></ul><ul><ul><li>scala> <a>Sounds <tag/> good</a>.text </li></ul></ul><ul><ul><li>res8: String = Sounds good </li></ul></ul><ul><ul><li>方法用于找元素 byTag </li></ul></ul><ul><ul><li> 是所有中找元素 byTag </li></ul></ul>
  68. 68. 更进一步 之 XML 找东西 <ul><li>scala> <a><b><c>hello</c></b></a> &quot;b&quot; </li></ul><ul><li>res10: scala.xml.NodeSeq = <b><c>hello</c></b> </li></ul><ul><li>scala> <a><b><c>hello</c></b></a> &quot;c&quot; </li></ul><ul><li>res11: scala.xml.NodeSeq =NodeSeq() </li></ul><ul><li>scala> <a><b><c>hello</c></b></a> &quot;c&quot; </li></ul><ul><li>res12: scala.xml.NodeSeq = <c>hello</c> </li></ul><ul><li>scala> <a><b><c>hello</c></b></a> &quot;a&quot; </li></ul><ul><li>res13: scala.xml.NodeSeq =NodeSeq() </li></ul><ul><li>scala> <a><b><c>hello</c></b></a> &quot;a&quot; </li></ul><ul><li>res14: scala.xml.NodeSeq = <a><b><c>hello</c></b></a> </li></ul>
  69. 69. 更进一步 之 XML 元素值 <ul><li>@ 方法找元素属性值 </li></ul><ul><li>scala> val joe = <employee </li></ul><ul><li>name=&quot;Joe&quot; </li></ul><ul><li>rank=&quot;code monkey&quot; </li></ul><ul><li>serial=&quot;123&quot;/> </li></ul><ul><li>joe: scala.xml.Elem = <employee rank=&quot;code monkey&quot; name=&quot;Joe&quot; </li></ul><ul><li>serial=&quot;123&quot;></employee> </li></ul><ul><li>scala> joe &quot;@name&quot; </li></ul><ul><li>res15: scala.xml.NodeSeq = Joe </li></ul><ul><li>scala> joe &quot;@serial&quot; </li></ul><ul><li>res16: scala.xml.NodeSeq = 123 </li></ul>
  70. 70. 更进一步 之 XML 模式匹配 <ul><li>快捷的模式匹配 </li></ul><ul><li>def proc(node: scala.xml.Node): String = </li></ul><ul><li>node match { </li></ul><ul><li>case <a>{contents}</a> => &quot;It's an a: &quot; + contents </li></ul><ul><li>case <b>{contents}</b> => &quot;It's a b: &quot; + contents </li></ul><ul><li>case <a>{contents @ _*}</a> => &quot;It's an a: &quot; + contents </li></ul><ul><li>case <b>{contents @ _*}</b> => &quot;It's a b: &quot; + contents </li></ul><ul><li>case _ => &quot;It's something else.&quot; </li></ul><ul><li>} </li></ul>
  71. 71. 更进一步 之 Io 系列 <ul><li>写文件 </li></ul><ul><li>import java.io._ </li></ul><ul><li>val writer = new PrintWriter( new File( &quot;symbols.txt&quot; )) </li></ul><ul><li>writer write &quot;AAPL&quot; </li></ul><ul><li>writer.close() </li></ul><ul><li>读文件 </li></ul><ul><li>Source.fromFile( &quot;ReadingFile.scala&quot; ).foreach { print } </li></ul><ul><li>读网络文件 </li></ul><ul><li>import scala.io.Source </li></ul><ul><li>import java.net.URL </li></ul><ul><li>Source.fromURL( new URL( &quot;http://www.scala-lang.org/docu/files/api/index.html&quot; )).foreach { print } </li></ul><ul><li>读 xml </li></ul><ul><li>import scala.xml._ </li></ul><ul><li>val stocksAndUnits = XML.load( &quot;http://www.verycd.com/sto/feed&quot; ) </li></ul><ul><li>写 xml </li></ul><ul><li>XML save ( &quot;d:/123.xml&quot; ,stocksAndUnits, &quot;utf-8&quot; ) </li></ul>
  72. 72. 更进一步 之 Actor <ul><li>是一个类似线程的实体,拥有一个邮箱( mailbox )来接受信息。 </li></ul><ul><li>Scala Actor 线程模型可以这样理解:所有 Actor 共享一个线程池,总的线程个数可以配置,也可以根据 CPU 个数决定;当一个 Actor 启动之后, Scala 分配一个线程给它使用,如果使用 receive 模型,这个线程就一直为该 Actor 所有,如果使用 react 模型, Scala 执行完 react 方法后抛出异常,则该线程就可以被其它 Actor 使用。 </li></ul><ul><li>通过继承 scala.actors.Actor 并实现 act 方法来使用 </li></ul><ul><li>import scala.actors._ </li></ul><ul><li>object SillyActor extends Actor { </li></ul><ul><li>def act() { </li></ul><ul><li>for (i <- 1 to 5) { </li></ul><ul><li>println( &quot;I'm acting!&quot; ) </li></ul><ul><li>Thread.sleep(1000) </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  73. 73. 更进一步 之 Actor <ul><li>或者,你可以引入 Actor ,然后直接定义一个立即执行的 actor </li></ul><ul><li>import scala.actors.Actor._ </li></ul><ul><li>val seriousActor2 = actor { </li></ul><ul><li>for (i <- 1 to 5) </li></ul><ul><li>println( &quot;That is the question.&quot; ) </li></ul><ul><li>Thread.sleep(1000) </li></ul><ul><li>} </li></ul><ul><li>这两个都是直接运行的 actor ,但实际上 actor 是用于接受信息并处理的, </li></ul><ul><li>用 ! 发信息,用 receive 接受信息 </li></ul><ul><li>! 工作是异步的,想要同步的话用 !? 即可 </li></ul><ul><li>但是 ! 是要等到 receive 的返回的,会阻塞继续发送信息,那样的话用 !! 的 </li></ul><ul><li>Future 模式,它发出后会立刻返回执行,得到的时候才会阻塞 </li></ul><ul><li>? 用来倒下一个 mailbox 里的东西 </li></ul><ul><li>mailboxSize :邮箱中未被处理的信息数 </li></ul><ul><li>sender ! &quot;&quot; 相当于 reply(&quot;&quot;) // 用于返回信息 </li></ul>
  74. 74. 更进一步 之 Actor <ul><li>来个等待的例子 </li></ul><ul><li>import scala.actors.Actor._ </li></ul><ul><li>val echoActor = actor { </li></ul><ul><li>loop{ //while (true) </li></ul><ul><li>receive { </li></ul><ul><li>case msg => </li></ul><ul><li>println( &quot;received message: &quot; + msg) </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  75. 75. 更进一步 之 Actor <ul><li>具体是这样的,每一条信息进入到邮箱里,首先调用偏方法的 isDefinedAt 判断是 </li></ul><ul><li>否有对应的 case 用于匹配处理这条信息,而且只针对第一个满足匹配的进行处理 </li></ul><ul><li>,然后调用偏方法的 apply 方法 </li></ul><ul><li>如果你想要把当前的线程当成 actor 的话,可以用 Actor.self </li></ul><ul><li>receive 同时还提供了一个限时的方法 receiveWithin 后面接毫秒数,超时则退出 </li></ul><ul><li>(用 case TIMEOUT ) </li></ul><ul><li>react 和 receive 不同,它并不会返回东西,而是返回 Nothing ,只是执行运算,不 </li></ul><ul><li>会保存当前线程的调用堆栈,所以要比 receive 高效得多 </li></ul><ul><li>但由于不会返回,也就意味着跟随在 react 后边的都不会执行,因此, react 应作 </li></ul><ul><li>为 actor 最后的东西 </li></ul><ul><li>同样有 reactWithin </li></ul><ul><li>用 loop 的时候还有个方法 loopWhile </li></ul><ul><li>receive 和 react 的差别在于 receive 需要阻塞当前 Java 线程, react 则仅为阻塞当前 </li></ul><ul><li>Actor ,但并不会阻塞 Java 线程,因此 react 模式更适合于充分发挥 coroutine 带来 </li></ul><ul><li>的原生线程数减少的好处,但 react 模式有个缺点是 react 不支持返回。 </li></ul><ul><li>remoteActor, 远程的,多了注册,多了 alive 等方法,提供远程试用 </li></ul>
  76. 76. 更进一步 之 swing <ul><li>超简化的 swing ,呃,这块我没兴趣,所以我就没看,但是可以说比 groovy 和 java 都要简单 </li></ul><ul><li>import scala.swing._ </li></ul><ul><li>import event._ </li></ul><ul><li>object SampleGUI extends SimpleGUIApplication { </li></ul><ul><li>def top = new MainFrame { </li></ul><ul><li>title = &quot;A Sample Scala Swing GUI&quot; </li></ul><ul><li>val label = new Label { text = &quot;hello&quot; } </li></ul><ul><li>val button = new Button { text = &quot;Click me&quot; } </li></ul><ul><li>contents = new FlowPanel { </li></ul><ul><li>contents += label </li></ul><ul><li>contents += button </li></ul><ul><li>} </li></ul><ul><li>listenTo(button) </li></ul><ul><li>reactions += { </li></ul><ul><li>case ButtonClicked(button) => </li></ul><ul><li>label.text = &quot;You clicked!&quot; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  77. 77. 更进一步 之 2.9.0.1 <ul><li>加入了平行集合类,在执行 `foreach`, `map`, `filter` 会充分使用多核处理 </li></ul><ul><li>App trait ,替代了 Application ,快速的应用特质 </li></ul><ul><li>延迟初始化的 trait </li></ul><ul><li>REPL(read-eval-print-loop) 强化, Runner 强化 </li></ul><ul><li>新的一些 annotation </li></ul><ul><li>更强大的 try catch finally </li></ul><ul><li>新的 sys 包,集合新加入了 collectFirst, maxBy, minBy, span, inits, tails, permutations, combinations, subsets 等方法 </li></ul><ul><li>N 多 bug 修复 </li></ul>
  78. 78. 更进一步 之 scala 图书

×