zoukankan      html  css  js  c++  java
  • Scala 快速入门

    scala

    • Scalable 编程语言
    • 纯正的的面向对象语言
    • 函数式编程语言
    • 无缝的java互操作

    scala之父 Martin Odersky

    1. 函数式编程

    • 函数式编程(functional programming) 或称函数程序设计,又称泛函编程,是一种编程范型
    • 它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。
    • 函数编程语言最重要的基础是λ演算(lambda calculus), 而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。
    • 函数式编程强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。

    1.1 函数式编程的重要概念

    使用纯函数编程, 纯函数是没有副作用的函数

    1.副作用
    所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

    函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

    var x = 1
    def XplusY_v1(y: Int) = x+y
    def XplusY_v2(y: Int) = {x = x+y; x}
    

    这里 XplusY_v2对 x 就有副作用, 函数执行之后 x 的状态会发生变化
    而 XplusY_v1 执行之后不会改变 x 的值, XplusY_v1是纯函数

    2.引用透明性

    定义: 如果f(x)的参数和函数体都是引用透明的, 那么函数f是纯函数
    特点: 对于相同的输入, 总是得到相同的输出.就是说,表达式的值不依赖于值可以改变的全局状态。

    var x = new StringBuild("Hello")
    var y = x.append("world")
    var z = x.append("world")
    

    上面形同的表达式x.append("world")得到的结果不同, 由于x是一个值可以改变的变量

    3.不变性(Immutablity)
    为了获得透明性, 任何值都不能改变

    4.函数是一等公民
    (First-class Function)
    函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

    5.只有表达式
    一切都是计算, 函数式编程中只有表达式, 变量, 函数都是表达式

    "表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。也就是说,每一步都是单纯的运算,而且都有返回值。

    6.闭包和高阶函数

    函数编程支持函数作为第一类对象,有时称为 闭包或者 仿函数(functor)对象。实质上,闭包是起函数的作用并可以像对象一样操作的对象。

    高阶函数(Higher order Function)可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。

    7.表达式求值策略

    • 严格求值
    • 非严格求值
    • 惰性求值

    8.递归函数
    递归实现循环: 尾递归

    1.2 函数式编程的优势

    • 生产效率高
    • 易于推理
    • 并行计算
    • 多核计算

    2. MacOS安装scala开发环境

    3步走:

    1. 安装scala
      brew install scala
    2. 安装sbt
      brew install sbt
    3. Intellj IDEA上scala ,sbt插件下载

    3. Scala 类型体系

    type1

    4. Scala求值策略

    Scala有两种求值策略
    - Call By Value 对函数实参求值,且只求一次,如果作为参数值需要对表达式先进行求值
    - Call By Name 对函数实参每次在函数体内被调用时都会求值

    通常使用Call By Value
    如果函数形参以 => 开头,那么会使用Call By Name
    def foo(x: Int) = x // call by value
    def foo(x: => Int) = x //call by name

    例子

    def test1(x: Int, y: Int): Int = x * x
    def test2(x: => Int, y: => Int): Int = x * x
    
    计算过程:
    
    test1(3+4, 8) | test2(3+4, 8) |  test1(7, 2 *4)  | test2(7, 2 *4)
    test1(7, 8)   | (3+4)*(3+4)   |  test1(7, 8)     | 7*7
    7*7           | 7*(3+4)       |  7*7             | 49
    49            | 7*7           |  49              | 
                  | 49            |                  |
    
    def bar1(x: Int, y: =>Int) = 1
    def bar2(x: => Int, y: =>Int) = 1
    def loop(): Int = loop
    
    bar1(loop, 1) 死循环, 这里实参一直带求值loop, 一直没法拿到值
    bar2(loop, 1) 表达式值为1 
    

    5. Scala函数

    scala中函数是第一等公民:

    1. 把函数作为实参传给另一个函数
    2. 把函数作为返回值
    3. 把函数赋值给变量
    4. 把函数存储在数据结构中

    在Scala中函数和普通变量一样, 同样也具有函数类型

    5.1 函数类型

    在Scala中, 函数类型格式为 A => B
    表示一个接受类型A的参数, 并返回类型B的参数, 如 Int => String

    5.2 高阶函数

    用函数作为形参或者返回值的函数, 称为高阶函数

    def operate(f: (int, int) => Int) = {
        f(4, 4)
    }
    
    def greeting() = (name: String) => {"hello" + " " + name} // 匿名函数
    

    5.3 匿名函数

    匿名函数就是函数常量, 也称为函数文字量
    scala中匿名函数的格式为:
    (形参列表) => (函数体)

    scala> (x: Int, y: Int) => x+y
    res2: (Int, Int) => Int = $$Lambda$1209/886693791@35c8be21
    
    scala> res2(1, 4)
    res3: Int = 5
    

    5.4 柯里化函数(curried function)

    柯里化函数把具有多个参数的函数转换成一条函数链, 每个节点上是单一参数

    下面两个例子的函数定义是等价的:

    def add(x: Int, y: Int) = x + y
    def add(x: Int)(y: Int) = x + y //scala里柯里化的语法

    def curriedAdd(x: Int)(y: Int) = x + y
    
    curriedAdd(1)(2)    //4
    
    val addOne = curriedAdd(1)_     // Int => Int
    addOne(2)   //3
    

    5.5 递归函数

    递归函数是函数式编程中实现循环的一种技术

    def factorial(n: Int): Int = {
        if (n == 0) 1 else n * factorial(n-1)
    }
    

    尾递归

    @annotation.tailrec
    def factorial(n: Int, m: Int): Int = {
        if (n == 0) m else factorial(n-1, n * m)
    }
    

    @annotation.tailrec 告诉 scala使用尾递归, 这里内存中开辟一个栈用来存储m的值, 而不是n个栈来存储计算中间结果

    5.6 例子

    def sum(f: Int => Int)(a: Int)(b: Int): Int = {
        @annotation.tailrec
        def loop(n: Int, acc: Int): Int = {
            if (n > b) acc
            else loop(n + 1, acc + f(n))
        }
        loop(a, 0)
    }
    
    sum(x => x)(1)(3) // 6
    
    sum(x => x * x)(1)(3) //14
    
    val s1 = sum(x => x * x)_  // 偏函数, _ 通配符用来匹配后面的参数
    s1(1)(3)  //14
    

    说明:
    1.上面是个科里化函数, 有三个形式参数

    • 函数f, 函数类型 Int > Int
    • 形参a, 类型Int
    • 形参b, 类型Int

    2.函数中定义了一个尾递归函数 loop, 实现相加
    3.sum(x => x), 其中 x => x 是一个匿名函数

    6. Scala 集合

    scala.collection.immutable

    6.1 List[T]

    T 表示泛型

    
    // :: 连接操作符
    val a = List(1, 2, 3, 4)
    val b = 0 :: a
    //a: List[Int] = List(1, 2, 3, 4)
    //b: List[Int] = List(0, 1, 2, 3, 4)
    
    // Nil表示一个空列表
    // 先 z 连接 Nil, 然后 y 连接 z ...
    val c = "x" :: "y" :: "z" :: Nil
    //c: List[String] = List(x, y, z)
    
    // Any 类型
    val d = a ::: c
    //d: List[Any] = List(1, 2, 3, 4, x, y, z)
    
    // 返回List的第一个元素
    a.head
    c.head
    d.head
    //res0: Int = 1
    //res1: String = x
    //res2: Any = 1
    
    // 返回除了第一个元素之外元素组成的 List
    a.tail
    c.tail
    d.tail
    
    //res3: List[Int] = List(2, 3, 4)
    //res4: List[String] = List(y, z)
    //res5: List[Any] = List(2, 3, 4, x, y, z)
    
    a.isEmpty
    Nil.isEmpty
    //res6: Boolean = false
    //res7: Boolean = true
    
    def walkthru(l : List[Int]): String = {
      if (l.isEmpty) ""
      else l.head.toString + walkthru(l.tail)
    }
    
    walkthru(List(1, 3, 5, 7))
    
    //walkthru: walkthru[](val l: List[Int]) => String
    //res8: String = 1357
    
    

    其他方法

    
    a.filter(x => x%2 == 1)
    //res9: List[Int] = List(1, 3)
    
    "hello life".toList
    //res10: List[Char] = List(h, e, l, l, o,  , l, i, f, e)
    
    "hel 89 life".toList.filter(x => Character.isDigit(x))
    //res11: List[Char] = List(8, 9)
    
    "hel 89 life".toList.takeWhile(x=>x!='9')
    //res12: List[Char] = List(h, e, l,  , 8)
    
    // _ 通配符
    c
    c.map(x => x.toUpperCase)
    c.map(_.toLowerCase)
    
    //res13: List[String] = List(x, y, z)
    //res14: List[String] = List(X, Y, Z)
    //res15: List[String] = List(x, y, z)
    
    a
    a.filter(_ % 2 == 1).map(_ + 10)
    //res16: List[Int] = List(1, 2, 3, 4)
    //res17: List[Int] = List(11, 13)
    
    
    val q = List(a, List(5, 6, 7))
    q.map(_.filter(_%2 == 0))
    q.flatMap(_.filter(_%2 == 0))
    //q: List[List[Int]] = List(List(1, 2, 3, 4), List(5, 6, 7))
    //res18: List[List[Int]] = List(List(2, 4), List(6))
    //res19: List[Int] = List(2, 4, 6)
    

    6.2 归约操作

    6.2.1 reduceleft

    reduceLeft(op: (T,T) => T)

    a
    a.reduceLeft((x, y) => x+y)
    a.reduce(_ + _)
    // res20: List[Int] = List(1, 2, 3, 4)
    // res21: Int = 10
    // res22: Int = 10
    

    6.2.2 foldLeft

    foldLeft(z: U)(op: (U, T) => U)
    a.foldLeft(1)(_ + _)

    a
    a.foldLeft(1)(_ + _)
    // res20: List[Int] = List(1, 2, 3, 4)
    // res23: Int = 11
    

    7. Range & Stream & tuple & Map

    7.1 Range & Stream

    1 to 4
    (1 to 7 by 2).toList
    1 until 6
    //res24: scala.collection.immutable.Range.Inclusive = Range 1 to 4
    // res25: List[Int] = List(1, 3, 5, 7)
    // res26: scala.collection.immutable.Range = Range 1 until 6
    
    // Stream 惰性求值
    1 #:: 2  #:: 3  #:: Stream.empty
    //scala.collection.immutable.Stream[Int] = Stream(1, ?)
    val stream = (1 to 1000000).toStream
    //res28: scala.collection.immutable.Stream[Int] = Stream(1,?)
    
    stream.tail
    stream.head
    //res28: scala.collection.immutable.Stream[Int] = Stream(2, ?)
    //res29: Int = 1
    

    7.2 tuple

    (1, 2)
    val tuple1 = (3, "hello", (1, "we"))
    tuple1._1
    tuple1._3._1
    // res30: (Int, Int) = (1,2)
    // tuple1: (Int, String, (Int, String)) = (3,hello,(1,we))
    // res31: Int = 3
    // res32: Int = 1
    
    def sumSq(in: List[Int]): (Int, Int, Int) = {
      in.foldLeft((0,0,0))((t,v) => (t._1 + 1, t._2 + v, t._3 + v*v))
    }
    a
    sumSq(a)
    //sumSq: sumSq[](val in: List[Int]) => (Int, Int, Int)
    // res33: List[Int] = List(1, 2, 3, 4)
    // res34: (Int, Int, Int) = (4,10,30)
    
    

    7.3 Map(K, V)

    // 键的类型要一致, 值得类型可以不一致
    val map = Map(1 -> "david", 9 -> "ds")
    map(9)
    map.contains(1)
    map.contains(2)
    //scala.collection.immutable.Map[Int,String] = Map(1 -> david, 9 -> ds)
    // String = ds
    // Boolean = true
    // Boolean = false
    
    map.keys
    map.values
    
    // 下列操作map自身是不变的
    map + (8 -> 3)
    map
    map - 1
    map
    
    //scala.collection.immutable.Map[Int,Any] = Map(1 -> david, 9 -> ds, 8 -> 3)
    // Map(1 -> david, 9 -> ds)
    // scala.collection.immutable.Map[Int,String] = Map(9 -> ds)
    // scala.collection.immutable.Map[Int,String] = Map(1 -> david, 9 -> ds)
    
    
    // 添加多个元素, 如果添加的key已经存在, 则更新
    map ++ List(2 -> "Alice", 1-> "Hello")
    //Map(1 -> Hello, 9 -> ds, 2 -> Alice)
    
    map -- List(2, 1, 9)
    // Map()
    // 如果key不存在则忽略 
    

    7.4 快排

    def qSort(a: List[Int]): List[Int] = {
      if (a.length < 2) a
      else qSort(a.filter(a.head > _)) ++
      a.filter(a.head == _) ++
      qSort(a.filter(a.head < _))
    }
    
    qSort(List(1, 4, 2, 3, 9, 5))
    //res46: List[Int] = List(1, 2, 3, 4, 5, 9)
    




  • 相关阅读:
    关于gitlab怎样merge request的流程
    有访问权限的gitlab如何把上面的代码clone到本地
    macpro终端打开mysql
    Hbase实验:java创建和删除table
    齐次递推式拆数学式
    一些生成函数
    圆锥表面曲线方程
    扩展欧拉降幂
    scanf读入有空格字符串
    线性筛素数的一个用途
  • 原文地址:https://www.cnblogs.com/nowgood/p/Scalarumen.html
Copyright © 2011-2022 走看看