zoukankan      html  css  js  c++  java
  • Scala学习——Brief Scala Tutorial

    因为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 structureidentity是个啥
    • 提供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: " + derive(exp, "x"))
      println("Derivative relative to y: " + 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)泛型

  • 相关阅读:
    C#特性
    C#继承
    对FileStream的几种属性和方法认识
    C# Parallel用法
    c#发布补丁
    WebApi接收接收日期格式参数时,日期类型(2019-10-08T16:00:00.000Z)后台接收时间少8小时问题
    c# 基于WebApi的快速开发框架FastFramework
    c# webapi结合swagger的使用
    windows服务autofac注入quartz任务
    c# autofac结合WebApi的使用
  • 原文地址:https://www.cnblogs.com/captainlucky/p/4630011.html
Copyright © 2011-2022 走看看