zoukankan      html  css  js  c++  java
  • scala(一)方法&函数

    写在前面

    众所周知,scala一向宣称自己是面向函数的编程,(java表示不服,我是面向bean的编程!)那什么是函数?

    在接触java的时候,有时候用函数来称呼某个method(实在找不出词了),有时候用方法来称呼某个method,虽然method的中文翻译就是“方法”,但对于java来说,方法和函数是等价的,或者说没有函数这个概念。

    而对于scala,这两者似乎有一个较为明确的边界。

    你会发现满世界的函数,而你却在写方法

    Scala 方法&函数

    方法

    Scala的方法和java可以看成是一样的,只是多了点语法糖。

    比如无参方法在申明时可以不加括号,甚至在调用过程也不用加括号

    def f = 1+1
    println(f)

    比如方法可以添加泛型规则,这在java中只能在类申明

    def f[T](t: T) = {t}

    还有其它很多细节语法,遇到才深入吧

    一般而言只要知道函数的结构就行(但是我想说,spark的代码就没有一个函数长成这样的啊..),请忽略下图的“函数”字样,其实就是方法

     

    方法应用

    def method(): Unit ={
      //本地方法
      def print(str:String): Unit ={
        println(str)
      }
      print("hello")
    }

    方法的语法还是跟java差不多的,只是有些可以省略而已。

    比较重要的就是本地方法,即方法中嵌套方法

    函数

    Scala的函数是基于Function家族,0-22,一共23个Function Trait可以被使用,数字代表了Funtcion的入参个数

    函数语法

    下面这四个函数的意义是一样的

    // println(fun1)
    // println(fun2)
    // println(fun3)
    // println(fun4)
    // 都为<function2>
    val fun1 = new Function2[Int,Int,Int]() {
      override def apply(v1: Int, v2: Int): Int = {
        v1+v2
      }
    }
    
    val fun2 = new ((Int, Int) => Int)() {
      override def apply(v1: Int, v2: Int): Int = {
        v1+v2
      }
    }
    
    val fun3 = (v1:Int,v2:Int) => v1+v2
    
    // _可以把method转换成function
    val fun4 = fun4Method _
    def fun4Method(v1:Int,v2:Int): Int = {
      v1+v2
    }

    一般我们都采用第三种fun3定义方式,也是最难懂的一个定义方式。具体结构参考下图

     

    那函数有什么用呢?

    Java里只有方法都能适应一切需求,那scala又提出函数的概念肯定有意义。

    1.函数可以直接赋值给变量,可以让函数很方便的传递

    2.闭包(closure),可以把灵活操作代码块,从而引申出其他灵活的语法

    函数应用

    在spark中,有很多方法入参中使用函数的场景,比如如下函数

    defrunJob[T,U](fun: Iterator[T] => U ,resHandler: (Int, U) => Unit): Unit ={
      //忽略里面的逻辑
    }

    其中的fun和resHandler都是函数

    Fun是入参为Iterator[T],返回值为U的函数,一个入参的函数其实就是Function1的实例

    resHandler是入参为Int和 U无返回值的函数,二个入参的函数其实就是Function2

    模拟spark中常见的一段代码语法,拿一个普通scala类型的例子来说

    //模拟spark的runJob方法
    def runJob[T,U](fun: Iterator[T] => U ,resHandler: (Int, U) => Unit): Unit ={
      val listBuffer = new ListBuffer[T]
      listBuffer.append("h".asInstanceOf[T])
      listBuffer.append("e".asInstanceOf[T])
      listBuffer.append("l".asInstanceOf[T])
      listBuffer.append("l".asInstanceOf[T])
      listBuffer.append("o".asInstanceOf[T])
      //这里调用函数其实用到了伴生对象的概念,fun(xxx)就是fun.apply(xxx)
      val res = fun(listBuffer.iterator)
      //spark中,这里是每个partition的数据都存入arr,这里做模拟就一个partition了:)
      resHandler(0,res)
    }
     
    //模拟调用runJob的方法
    def main(args: Array[String]): Unit = {
      val arr = new Array[String](1)
      //fun函数的实际逻辑
      val fun = (it:Iterator[String]) => {
        val sb = new StringBuilder()
        while (it.hasNext)
          sb.append(it.next())
        sb.toString()
      }
    
      //resHandler函数的实际逻辑
      val resHandler = (i:Int,res:String) => arr(i) = res
      runJob[String,String](fun ,resHandler)
      println(arr.mkString(""))
    }

    其实就是传递函数的逻辑,和java的匿名类差不多(只有一个方法的匿名类),只是多了点语法糖

    这么做的好处也是不言而喻的

    1.可以构造出更抽象的方法,使得代码结构更简洁

    2.spark的思想就是lazy,而函数传递也是一个lazy的过程,只有在实际触发才会执行

    偏函数

    英文为PartialFunction,不知道这么翻译对不对,貌似都这么叫。

    PartialFunction其实是Funtion1的子类

    参考源码

    trait PartialFunction[-A, +B] extends (A => B)

    A => B就是标准的函数结构

    那PartialFunction有什么作用呢?

    模式匹配!

    PartialFunction最重要的两个方法,一个是实际的操作逻辑,一个是校验,其实就是用来做模式匹配的。

    参考资料

    《Scala编程》

  • 相关阅读:
    操作系统:DOS
    袁氏-人物:袁淑
    移植linux-2.6.32.2到qq2440
    qq2440启动linux后出现错误提示request_module: runaway loop modprobe binfmt-464c
    qq2440启动linux后插入u盘出现usb 1-1: device descriptor read/64, error -110,usb 1-1: device not accepting address 8, error -110
    ubuntu14.04 64bit安装teamviewer
    vi 的使用
    添加了环境变量,然而交叉编译器还是无法运行的解决方案
    linux下route命令使用实战
    ubuntu14.04纯命令行下连接有线网和无线网
  • 原文地址:https://www.cnblogs.com/ulysses-you/p/7551188.html
Copyright © 2011-2022 走看看