`
诺铁
  • 浏览: 34777 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

诺铁的scala入门心得 for java程序员

阅读更多

看完了Martin Odersky的《Programming in Scala》。作者是写java编译器的大牛,技术够强,书写的一般,我个人感觉如果是被“scala是更好的java”这句传言吸引而来的的java程序员,恐怕会很快被吓跑----scala的代码跟java代码实在是太不一样。反而如果之前学过haskell这样的纯函数式编程语言,学scala不会有太多障碍。我个人建议想学scala的程序员先看完learnyourhaskellforgreatgood ,对函数式编程有个纯粹的认识后再来看scala在java虚拟机上能实现到什么程度。

 

我写这篇博客记录一下我觉得对java程序员来说比较需要掌握的scala编程要素

 

  1. scala解释器
    下载安装装好scala,把bin加入path, 然后可以用文本文件编写scala脚本,在命令行下运行scala -i filepath加载脚本文件,然后就可以在scala提示符scala>里面“玩弄”你写在脚本里的函数,对象等等
    修改了文件后可以在scala>里面输入:l filepath来加载 
    用好解释器对学习scala非常有帮助,所以特别说一下
  2. 头等函数(first-class function)
    函数跟类一样是顶级元素,所以可以直接在代码里定义函数,不需要放在类里作为“方法”
    def sum(x:Int, y:Int, z:Int) :Int = {
      x + y + z
    }
     
    scala>sum(1,2,3)
    res0: Int = 6
     头等函数跟变量一样可以传递,可以被赋值(scala里需要以偏函数的形式,haskell可以直接赋值)
    scala>val s = sum _   //sum函数赋值给变量s
    scala>s(1,2,3)            
    res: Int = 6
  3. 函数字面值
    可以不给函数起名字,直接把函数定义赋值给变量
    scala> val s2 = (x:Int, y:Int ,z:Int) => x + y + z
    s2: (Int, Int, Int) => Int = <function3>
    
    scala> s2(1,2,3)
    res1: Int = 6
     有必要认识函数的这种写法,因为会有助于看懂scala的库里的接口,比如List类里的filter方法
    def filter (p: (A) ⇒ Boolean): List[A]
    这个函数接受一个谓词(其实就是一个函数)p,这个p无所谓名字,只要是能够接受一个元素作为参数,返回Boolean型就行了
    scala> val l1 = List(1,2,3,4,5)
    l1: List[Int] = List(1, 2, 3, 4, 5)
    
    scala> l1.filter(x => x > 3)  //过滤出大于三的结果,返回到新集合里
    res4: List[Int] = List(4, 5)
    
    scala> l1.filter(x => x % 2 == 0)  //过滤出偶数
    res7: List[Int] = List(2, 4)
  4. 占位符和偏函数(partially applied function,也有翻译为部分应用函数的)
    占用符,就是_, 看scala的代码会看到大量的_, 
    有些地方这个_的意思跟*一样作为通配符,只是scala里*不是内置语法元素,是可以用来做方法名和函数名的,以便用户可以方便开发自己的DSL
    scala> def *(x:Int, y:Int) = x * y  //用*作为函数名
    $times: (x: Int, y: Int)Int
    
    scala> *(2,3)
    res8: Int = 6
     scala> import scala.collection._
    import scala.collection._
    这个就是跟*一样的效果了
    
     更重要的作用是用做偏函数的占位符,比较给力
    scala> def sum(x:Int, y:Int, z:Int):Int = x + y + z
    sum: (x: Int, y: Int, z: Int)Int
    
    scala> val s = sum(2, 3, _:Int)
    
    在这里,给sum函数传入2,3作为前两个参数,但是不传入第3个函数,而是传入一个占位符,于是产生了只接受一个参数的函数s
    s: (Int) => Int = <function1>  //函数的签名变成了一个参数
    
    scala> s(4)                                // 2 + 3 + 4
    res9: Int = 9
    
    这个东东就是所谓的偏函数(部分应用函数)
    
     占位符的应用可以很灵活,可以占任何位置
    scala> def say(greeting:String, title:String, name:String) = println(greeting + "," + title + " " + name)
    say: (greeting: String, title: String, name: String)Unit
    
    scala> val callNotyy = say(_:String, "Mr", _:String)
    callNotyy: (String, String) => Unit = <function2>
    
    scala> callNotyy("hello","notyy")
    hello,Mr notyy
     
  5. 模式匹配
    用函数式编程的风格写代码首先要适应的就是“模式匹配”,先来个简单的例子
    def sayInt(i:Int): String = i match {
      case 1 => "one"
      case 2 => "two"
      case 3 => "three"
      case _ => "unknown int"   //_作为通配符,提供一个默认case
    }
    
    scala> sayInt(1)
    res0: String = one
    
    scala> sayInt(2)
    res1: String = two
    
    scala> sayInt(4)
    res4: String = unknown int
    从最基本的概念来说和switch很像,但是灵活的多,上例只是最简单的常量模式匹配。
     模式匹配机制可以匹配各种“东西”,比如说匹配一个列表中的元素:
    def zeroStartList(l:List[Int]) = l match {
      case List(0, _, _) => println("found it") //匹配3个元素的列表,并且第一个元素是0
      case _ => println("not found")
    }
    
    scala> zeroStartList(List(0,1,2))
    found it
    
    scala> zeroStartList(List(1,1,2))
    not found
     还可以匹配类型
    def size(x: Any) = x match {
      case s: String => s.length
      case m: Map[_, _] => m.size
      case _ => 1
    }
    
    scala> size("abc")
    res7: Int = 3
    
    scala> size(Map(1 -> 'a', 2->'b'))
    res11: Int = 2
     
  6. case class与模式匹配还有守卫(guard)
    构造器模式匹配是模式匹配的真正强大之出,但是需要引入样本类(case class)的概念
    case class User(name:String, age:Int, position:String)
    
    def sayHello(user:User) = user match {
      case User(name, _, "admin") => println("hello,admin " + name)
      case User(_, _, _) => println("how do you get here! guards!!")
    }
    这个模式匹配可以理解为“形如”,意会吧,看到这里,上面两行代码应该不难理解吧
    scala> sayHello(User("notyy",35,"admin"))
    hello,admin notyy
    
    scala> sayHello(User("badguy",35,"thief"))
    how do you get here! guards!!
    
    
     构造器模式可以深层匹配,稍微改下代码:
    case class Email(name:String,domain:String)
    
    case class User(name:String, age:Int, position:String, email:Email)
    
    def sayHello(user:User) = user match {
      case User(name, _, "admin",Email(_, "notyy.iteye.com")) => println("hello,admin " + name)
      case User(_, _, _, _) => println("how do you get here! guards!!")
    }
    这里我们不仅匹配User里的内容,还匹配到User里的Email里的内容
    
    scala> sayHello(User("notyy",35,"admin",Email("notyy","somedomain.com")))
    how do you get here! guards!!
    
    scala> sayHello(User("notyy",35,"admin",Email("notyy","notyy.iteye.com")))
    hello,admin notyy
     我们再来结合guards,以便对参数进行更细致的匹配:我们改下上面的代码,对年龄不满18的用户进行限制
    def sayHello(user:User) = user match {
      case User(name, age, _, _) if age < 18 => println("you are too young to come here," + name + " ;-) ,guards!")
      case User(name, _, "admin",Email(_, "notyy.iteye.com")) => println("hello,admin " + name)
      case User(name, _, _, _) => println("how do you get here!" + name + ", guards!!")
    }
    
    scala> sayHello(User("notyy",17,"admin",Email("notyy","notyy.iteye.com")))
    you are too young to come here ;-) ,guards!
    
     

  7. for 表达式
  8.  for循环要拿出来说一下。如果是从纯函数式编程语言如haskell转过来,会知道函数式编程语言里一般木有循环的。代之的是递归。更常用的是一些通用的循环函数框架,foreach, filter, map等
    val users = List(
      User("tom", 17, "admin", Email("tom", "notyy.iteye.com")),
      User("notyy", 35, "admin", Email("notyyy", "notyy.iteye.com")),
      User("badguy", 35, "admin", Email("badguy", "badguys.com"))
    )
    
    scala> users.foreach(sayHello)
    you are too young to come here,tom ;-) ,guards!
    hello,admin notyy
    how do you get here!badguy, guards!!
    
    List类里的foreach方法的定义是
    def foreach (f: (A) ⇒ Unit): Unit
    [use case] Applies a function f to all elements of this list
    这方法的意思就是对集合的每个元素应用传入进来的函数f
     这是我喜欢的编码风格,不过喜欢for循环的也可以用scala里的for表达式
    for (user <- users)
      sayHello(user)
     还可以在for里面结合模式匹配。。。
    for (User(name,_ ,pos ,_) <- users)
      println("name=" + name + ",pos=" + pos)
     如此强力。。。
    scala的特性太多,语法糖多的有点甜腻,写完此文总算记住了一些,接下来研究liftweb框架,用上面那些基础基本上可以看下去了。《scala编程》这本书作为入门书虽然是艰深了点,作为参考手册倒是相当不错的,可以常备案头常翻翻

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics