因为Spark项目需要,学习Scala编程。

从官网文档入手:http://www.scala-lang.org/documentation/

首先从他的Older Documentation入手。

第一篇是Brief Scala Tutorial

只有20页,对于有Java基础的人来说上手很快

其中有几点值得注意

(1)函数式编程

object Timer {
  def oncePerSecond(callback: () => Unit) {
    while (true) { callback(); Thread sleep 1000 }
  }
  def timeFlies() {
    println("time flies like an arrow...")
  }
  def main(args: Array[String]) { oncePerSecond(timeFlies)}
}

官网给出的解释是

The type of this function is written () => Unit and is the type of all functions which take no arguments and return nothing (the type Unit is similar to void in C/C++).

这段不知道怎么翻译合适。

(2)匿名方法

object TimerAnonymous {
  def oncePerSecond(callback: () => Unit) {
    while (true) { callback(); Thread sleep 1000 } }
  def main(args: Array[String]) { oncePerSecond(() =>
    println("time flies like an arrow...")) }
}

用匿名方法的话编程更简单直白,在main方法中直接用=>分开了方法名参数及方法体。和上面的例子效果是相同的。

(3)Scala的class可以带参数:

class Complex(real: Double, imaginary: Double) {
def re() = real
def im() = imaginary
}

这样的语句定义了一个单例对象:一个有且仅有一个实例的类。object语句在定义了一个叫HelloWorld的类的同时还定义了一个叫HelloWorld的实例。这个实例在第一次使用的时候会进行实例化。聪明的读者可能会发现main函数并没有使用static修饰符,这是由于静态成员(方法或者变量)在Scala中并不存在。Scala从不定义静态成员,而通过定义单例object取而代之。

在def re()=real中没有指定返回值类型,而是由编译器根据“=”右边的类型来判断该方法的返回值类型。当然编译器不是总能推断出正确的变量类型,这就需要编程人员在编程初期尝试去掉变量类型定义,如果编译器不报错的话就表示他可以推断类型,如果报错就还是老老实实地把类型加上。等到编的多了就知道什么可以什么不可以了。

当然,这里的re()和im()的括号是可以去掉的。

class Complex(real: Double, imaginary: Double) { 
  def re = real
  def im = imaginary
}

(4)继承与重写

class Complex(real: Double, imaginary: Double) { 
  def re = real
  def im = imaginary
  override def toString() =
    "" + re + (if (im < 0) "" else "+") + im + "i"
}

如果子类的方法重写了父类的方法,必须要有override修饰语

如果一个类没有继承任何类的话,隐式继承scala.AnyRef

(5)case class

对于处理树结构的数据很适用

abstract class Tree
case class Sum(l: Tree, r: Tree) extends Tree
case class Var(n: String) extends Tree
case class Const(v: Int) extends Tree

以上的Sum,Var和Const就是case class,与标准的class有以下几个区别

  • 不用new原语去实例化(e.g.可以直接写成Const(5),而不用new Const(5))
  • case类的构造器参数被当作公开值并可以直接被访问 e.g. 
    val x = Var("x")
    Console.println(x.name)
  • 已提供方法equals和hashCode的默认定义,work on the structure of the instances and not on their identity(英文水平让人抓狂啊)这里的instance structure和identity是个啥
  • 提供toString()默认定义,打印值的source form。e.g.the tree for expression x+1 prints as Sum(Var(x),Const(1))
  • 分解数据结构的时候用到了模式匹配

模式匹配的东西有点难,

def eval(t: Tree, env: Environment): Int = t match {
  case Sum(l, r) => eval(l, env) + eval(r, env)
  case Var(n) => env(n)
  case Const(v) => v
}

Environment的目的就是为了给变量赋值

一个熟练的面向对象的程序员可能想知道为什么我们不吧eval定义为Tree或者其之类的成员函数。我们事实上可以这么做。因为Scala允许条件类象普通类那样定义成员。决定是否使用模式匹配或者成员函数取决于程序员的喜好,不过这个取舍还和可扩展性有重要联系:
当你使用成员函数时,你可以通过继承Tree从而很容易的添加新的节点类型,但是另外一方面,添加新的操作也是很繁杂的工作,因为你不得不修改Tree的所有子类。
当你使用模式匹配是,形势正好逆转过来,添加新的节点类型要求你修改所有的对树使用模式匹配的函数,但是另一方面,添加一个新的操作只需要再添加一个模式匹配函数就可以了。

下面是模式匹配里的对符号求导数

首先看下导数的性质:

  • 和的导数就是导数的和
  • 如果符号等以求导的符号,则导数为1,否则为0
  • 常量的导数是0
def derive(t: Tree, v: String): Tree = t match {
  case Sum(l, r) => Sum(derive(l, v), derive(r, v))
  case Var(n) if (v == n) => Const(1)
  case _ => Const(0)
}

大概的意思是首先他会检查t是不是一个sum,如果fail了就检查是不是var,再fail检查是不是一个Const。

还是来个实际例子看一下:

def main(args: Array[String]) {
  val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y")))
  val env: Environment = { case "x" => 5 case "y" => 7 }
  println("Expression: " + exp)
  println("Evaluation with x=5, y=7: " + eval(exp, env))
  println("Derivative relative to x:\n " + derive(exp, "x"))
  println("Derivative relative to y:\n " + derive(exp, "y"))
}

输出:

Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y)))
Evaluation with x=5, y=7: 24
Derivative relative to x:Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0)))
Derivative relative to y:Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1)))

(6)traits

Scala的traits和Java中的interface类似,但有别于interface的是traits可以实现部分方法,并且可以继承多个。

Tutorial里的例子不是很直观,于是摘了网上的一个例子[1]

abstract class Animal {
def walk(speed:Int) def breathe() = {
println("animal breathes")
}
}

这里的抽象类Animal定义了walk方法,实现了breathe方法。

再看下Flyable和Swimable两个trait的实现:

trait Flyable {
def hasFeather = true
def fly
}
trait Swimable {
def swim
}

注意Flyable trait中有两个方法,一个是hasFeather方法,这个方法已经实现了,另一个方法是fly方法,这个方法只是定义没有实现,而Swimable trait只是定义个一个swim的方法,没有具体实现。

下面我们定义一种动物,它既会飞也会游泳,这种动物是鱼鹰 FishEagle,我们看下代码:

class FishEagle extends Animal with Flyable with Swimable {
def walk(speed:Int) = println("fish eagle walk with speed " + speed)
def swim() = println("fish eagle swim fast")
def fly() = println("fish eagle fly fast")
}

在类的实现中需要实现抽象类Animal的walk方法,也需要实现两个特征中定义的未实现方法。

下面main方法代码:

object App {
def main(args : Array[String]) {
val fishEagle = new FishEagle
val flyable:Flyable = fishEagle
flyable.fly val swimmer:Swimable = fishEagle
swimmer.swim
}
}

在main方法中,我们首先初始化了一个FishEagle对象,然后通过Flyable和Swimable trait来分别调用其fly和swim方法,输出结果如下:

fish eagle fly fast
fish eagle swim fast

trait的使用方法就是这样子了,它很强大,抽象类能做的事情,trait都可以做。它的长处在于可以多继承。

trait和抽象类的区别在于抽象类是对一个继承链的,类和类之前确实有父子类的继承关系,而trait则如其名字,表示一种特征,可以多继承。

还有一个特点就是with:用关键字with可以混入更多的trait。如果类已经继承了类,就可以使用with混入trait。

class Animal
class Dog(val name: String) extends Animal with Friend{}

我们还可以在实例一级进行混入,这样的话就可以把特定的类的实例当做trait

class Cat(val name: String) extends Animal
val scat = new Cat("cat") with Friend
//这样scat就是Friend了

(7)泛型

 

参考文献
【1】
scala入门教程:scala中的trait



Scala学习——Brief Scala Tutorial的更多相关文章

  1. Scala学习(一)--Scala基础学习

    Scala基础学习 摘要: 在篇主要内容:如何把Scala当做工业级的便携计算器使用,如何用Scala处理数字以及其他算术操作.在这个过程中,我们将介绍一系列重要的Scala概念和惯用法.同时你还将学 ...

  2. Scala学习(五)---Scala中的类

    Scala中的类 摘要: 在本篇中,你将会学习如何用Scala实现类.如果你了解Java或C++中的类,你不会觉得这有多难,并且你会很享受Scala更加精简的表示法带来的便利.本篇的要点包括: 1. ...

  3. Scala学习随笔——Scala起步

    实验楼学习Scala语言的笔记,课程网址为https://www.shiyanlou.com/courses/490 一.Scala简介 Scala 是一门多范式的编程语言,类似于 Java .设计初 ...

  4. Scala学习1————scala开发环境搭建(windows 10)

    Scala开发环境搭建 先讲几点我学习scala的目的或者原因吧: JVM在企业中的霸主地位,Scala也是JVM上的语言,很有可能未来会从Java过度到Scala也不是不可能. 先进的函数式编程和面 ...

  5. Scala学习(八)---Scala继承

    Scala继承 摘要: 在本篇中,你将了解到Scala的继承与Java和C++最显著的不同.要点包括: 1. extends.final关键字和Java中相同 2. 重写方法时必须用override ...

  6. Scala学习(六)---Scala对象

    Scala中的对象 摘要: 在本篇中,你将会学到何时使用Scala的object语法结构.在你需要某个类的单个实例时,或者想为其他值或函数找一个可以挂靠的地方时,你就会用到它.本篇的要点包括: 1. ...

  7. Scala学习资源

    Scala学习资源: Scala官方网站:http://www.scala-lang.org/ Scala github:https://github.com/scala/scala Twitter ...

  8. 机器学习(三)--- scala学习笔记

    Scala是一门多范式的编程语言,一种类似Java的编程语言,设计初衷是实现可伸缩的语言.并集成面向对象编程和函数式编程的各种特性. Spark是UC Berkeley AMP lab所开源的类Had ...

  9. Scala学习笔记 & 一些不错的学习材料 & 函数编程的历史八卦

    参考这篇文章: http://www.ibm.com/developerworks/cn/java/j-lo-funinscala1/ 这也是一个系列 严格意义上的编程范式分为:命令式编程(Imper ...

随机推荐

  1. Spring----最小化Spring配置

    在Spring的配置文件中,我们可以使用<bean>元素定义Bean,以及使用<constructor-arg>或着<property>元素装配bean,这对于包含 ...

  2. springboots Helloworld

    1.eclipse gradle 插件 HELP----MarketPlace----搜索 buildship点击安装 WINDOW----preferences--gradle 配置安装好的grad ...

  3. 初学者使用MySQL_Workbench 6.0CE创建数据库和表,以及在表中插入数据。

    标签: mysqlworkbench数据库 2013-10-09 20:17 19225人阅读 评论(14) 收藏 举报  分类: mysql(1)  版权声明:本文为博主原创文章,未经博主允许不得转 ...

  4. js如何判断IE浏览器的版本包括IE11

    IE浏览器真是个坑:从ie6以及以前IE版本,简直就是垃圾,不按照Mozilla国际组织的标准来,乱搞.搞得兼容性很差:   <script type="text/javascript ...

  5. Java Swing实战(一)JFrame和JTabbedPane容器

    概述: 项目是一个桌面程序,涉及标签和按钮组件.布局管理器组件.面板组件.列表框和下拉框组件等组件,以及Swing事件处理机制. 下面先从最基础的界面开始. /** * @author: lishua ...

  6. Java Singleton(单例模式) 实现详解

    什么是单例模式? Intend:Ensure a class only has one instance, and provide a global point of access to it. 目标 ...

  7. 修改request请求参数

    本质上来讲,request请求当中的参数是无法更改的,也不能添加或者删除: 但在后台程序中,一般对request的参数的操作,都是通过request的getParameter.getParameter ...

  8. CRM 安装过程 AD+SQL+CRM

    AD: 通过服务器管理器添加域服务,配置域服务器域名为crm5.lab. 注意:使用高级模式安装. 说明:服务器是windows server 2003 那么就选windows server 2003 ...

  9. Android 运行时权限处理(from jianshu)

    https://www.jianshu.com/p/e1ab1a179fbb 翻译的国外一篇文章. android M 的名字官方刚发布不久,最终正式版即将来临! android在不断发展,最近的更新 ...

  10. maven 依赖和坐标

    1.maven 坐标由groupId.artifactId.packaging.version.classifier定义.2.classifier 用来帮助定义构建输出的一些附属构件.如,*javad ...