zoukankan      html  css  js  c++  java
  • Spark(七) -- Scala快速入门

    Scala作为Spark的开发语言,想要成为Spark高手,精通Scala是必须要走的一条路
    然后一门语言并不是你想精通就能够精通的,更何况是Scala这种面向对象又面向函数的编程语言,个人觉得其学习的门槛会比C#,Java等面向对象语言要高
    所以,这篇文章是建立在有一点编程语言知识的基础上的(如学过C#或者Java等),其实所有语言都是大同小异的,学会了一门语言在学其他的就不会像刚开始那么吃力了,因为它们很多概念都是相通的
    本篇文章主要是介绍Scala本身的一些特性,以便以能够快速的上手开发,而对于真正要精通Scala,显然要付出的努力还要很多

    安装Scala的开发环境就不具体介绍了,请自行百度之。IDE使用的是Eclipse For Scala,下载地址:
    Eclipse For Scala

    本文大概从以下几个方面来介绍Scala:

    1. 声明变量的关键字
    2. 方法的定义格式
    3. 条件表达式
    4. 默认参数,带名参数和变长参数
    5. lazy变量
    6. 数组
    7. Map操作
    8. 元组
    9. 值函数
    10. 匿名函数
    11. 函数柯里化
    12. 高阶函数示例
    13. List序列
    14. case class和模式匹配

    Scala中声明变量的关键字只有两种:
    val和var,分别表示常量和变量的声明(在Scala提倡中尽量使用val而不是var)

    方法的定义格式:
    def 方法名(参数名:参数类型,…):返回值类型={方法体}
    如:

    def add(x:Int,y:Int):Int={
        x + y
    }

    定义了一个参数为两个Int类型,返回值也为Int类型的方法add,返回x+y的值
    相信已经有人注意到了,在Scala中,每个句子是不用以分号结束的(当然加上分号也没事),而且方法中不用return来返回,默认返回的是最后一行的值
    当方法没有返回值时表现形式为:

    def add():Unit={...}

    或者直接省略:Unit

    def add()={...}

    在调用方法的时候,如果该方法没有参数,可以省略括号,如:

    add//加上括号也没事,如add()

    条件表达式:

    和其他语言的if/else唯一的却别就是,Scala的if/else是有返回值的

    val x = 8
    val res = if(x > 7) 1 else 0

    如果x>7就返回1,否则返回0,赋值给res

    Scala中的while和do-while用法是和其他语言一样的,但是for的用法就不同了
    for循环语句的格式为:

    for(i <- 表达式){
        循环体
    }

    例如:

    for(i <- 1 to 10){
        println(i)
    }

    上面代码中,1 to 10会产生1-10中的每个数,i会迭代循环这10个数,迭代一次执行一次循环体。
    刚开始看肯定会很奇怪,<-这个符号是必须的,现在假设我们有一个arr数组,里面有1-10这10个数
    首先用C#的循环方式为:

    for(int i = 0;i < arr.Length;i++)
    {
        Console.WriteLine(arr[i]);
    }
    //或者foreach方式
    foreach(var i in arr)
    {
        Console.WriteLine(i);
    }

    在对比一下Scala的for循环:

    for(i <- 0 to arr.length){
        println(arr[i])
    }
    //for同时也可以当foreach使用
    for(i <- arr){
        println(i)
    }

    并且,在Scala中,for循环是可以添加if判断语句的,如:

    for(i <- 0 to 10 if i % 2 == 0){
        println(i)
    }

    上面代码的意思是,循环0-10,只打印出偶数
    Scala的循环表达式中没有continue和break语句,但是可以通过一个Boolean变量和嵌套函数中return来实现

    默认参数,带名参数和变长参数:

    这几个概念很简单,通过几行实例代码基本可以了解
    默认参数:

    def getName(name:String = "JChubby") = {...}

    调用getName时如果没有传参数,则会使用默认的JChubby

    带名参数:

    def showNum(x:Int,y:Int):Unit = {...}

    调用该方法时,参数可以不按顺序,但是要执行参数名:

    showNum(y = 2,x = 4)

    变长参数:

    def canChangeLength(x:Int*) = {...}

    调用时:

    canChangeLength(1,2,3,4,...)

    lazy变量:

    正常情况下使用val或者var声明变量时是直接分配内存空间使用的
    当使用lazy关键字时,这个常/变量只有在使用的时候才会被分配内存
    如在Scala命令行中输入下面的代码之后回车:

    lazy val a = 1

    这里写图片描述

    lazy(懒值)对应开销很大的初始化操作非常有用,如在读取一个很大的文件的时候,如果一开始并不马上使用,可以将其标记为lazy,直到文件真正使用的时候才分配内存空间

    数组:

    Scala中分为两种:
    定长数组:scala.collection.immutable.Array,一旦声明之后长度不可变
    变长数组:scala.collection.mutable.ArrayBuffer,动态数组

    定长数组使用:

    val arr = new Array[Int](3)//声明长度为3,类型为Int的Array数组(new可省略)
    
    //或者声明时直接赋值
    //编译器会自动推断类型为Int
    val arr = Array(1,2,3)
    
    //通过下标访问数组的方式为()而不是[],请注意!
    val a = arr(0)

    变长数组使用:

    val arrBuf = scala.collection.mutable.ArrayBuffer[Int]()
    //添加元素,相当于add
    arrBuf += 1
    //也可以一次性添加多个
    arrBuf += (1,2,3)
    //使用++=可以直接添加一个数组
    arrBuf ++= Array(1,2,3)
    //在指定位置插入若干个元素,在0位置插入1,2,3
    arrBuf.insert(0,1,2,3)
    //Scala中的函数除了通过.来调用之外也可以直接写成一下形式
    arrBuf insert (0,1,2,3)
    //之前的1 to 10 其实就是调用了1.to(10)这个to方法
    
    //移除指定位置的元素
    arrBuf remove 0
    //移除指定位置后的连续n个元素
    arrBuf remove 0,3
    //删除末尾的n个元素
    arrBuf trimEnd 3

    此外还有例如min,max等函数求最大最小等常用操作

    Map操作:

    和数组一样,Map同样也分为可变和不可变两种

    不可变Map的使用:

    //声明一个Map,包含两个键值对,->表示键值对应的关系
    val myMap = Map("JChubby" -> 22,"Looky" -> 21)

    不可变的Map中,一旦声明之后,该Map不可添加不可删除不可修改,只能查看,查看方式与可变Map一致

    可变Map的使用:

    val myMap = scala.collection.mutable.Map("JChubby" -> 22,"Looky" -> 21)
    //添加元素
    myMap += ("abc" -> 12,"bcd" -> 13)
    //删除元素
    myMap -= "abc"
    //修改元素
    myMap("JChubby") = 10
    //或者
    myMap += ("JChubby" -> 10)
    //查找元素
    myMap("JChubby")
    //或者使用getOrElse,该方法在取不到值的时候返回一个默认值,以免出现异常
    myMap getOrElse ("JChubby",-1)
    //遍历,使用的是k,v格式来进行遍历
    for((k,v) <- myMap){
        println(k + ":" + v)
    }
    //如果只要遍历k或者v,可以使用_占位符
    for((k,_) <- myMap){
        println(k)
    }
    //获取所有的key
    myMap.keySet
    //获取所有的value
    myMap.values

    元组:

    元组其实就是一个集合,但是可以存放各种不同类型的数据
    例如:

    val group = (1,2,"JChubby",3.0)
    //通过下标访问元组的格式为:元组名._下标 或者 元组名 _下标。如:
    group._0
    group _0
    //遍历元组格式为,productIterator为固定格式不可少
    for(element <- group.productIterator){
        ...
    }

    值函数:

    Scala中可以将函数赋值给一个变量,这个变量就称为值函数

    def add(x:Int,y:Int):Int = {
        x + y
    }
    
    //格式为方法名+空格+_
    var res = add _
    //之后可以将这个变量当做方法来用
    res(1,2)

    匿名函数:

    顾名思义,没有名字的函数,定义格式如下:
    (参数名:参数类型,…) => 表达式
    例如:

    (x:Int) => x + 3

    可以将匿名函数赋值给一个常量

    val func = (x:Int) => x + 3
    //直接调用常量
    func(7)

    上面的用法其实和直接定义一个有名的函数是一样的,匿名函数主要是当做函数的参数来传递使用
    例如scala.collection.mutable.ArrayBuffer的map方法,其参数要求是一个匿名函数

    scala.collection.mutable.ArrayBuffer.map((x:Int) => x +3)

    执行的结果是ArrayBuffer里面每个值都加3(map函数之后会介绍)

    函数柯里化:

    函数柯里化就是将原本有 很多参数 的函数,分成一个个只有 一个参数 的函数,每个函数的返回值都是 一个表达式 并且当做参数 传到下一个函数
    例如:

    def mul(x:Int,y:Int) = x + y
    //调用方式为
    mul(1,2)
    //柯里化后的函数为
    def mul(x:Int)(y:Int) = x + y
    //调用当时为
    mul(1)(2)
    //执行mul(1)时,返回的是1 + y,在将这个函数应用到2,得到 1 + 2

    柯里化是闭包的典型体现,具体柯里化的概念请百度之~

    高阶函数示例:

    数组的map函数

    val arr = Array(1,2,3)
    arr.map(1 + _)

    _表示数组中的每个元素,执行的结果为每个元素+1

    数组的filter函数

    arr.filter(_ > 2)

    _ > 2会将数组中大于2的元素过滤出来

    数组的reduce函数

    arr.reduce(_ + _)

    reduce是迭代运算,将数组中两个元素先执行操作,把结果作为一个元素继续和下一个元素进行操作,执行结果为:1+2=3,3+3=9,也就是求和

    List序列:

    List操作:

    val list = List(1,2,3)
    //获取头元素
    list.head
    //获取除了头元素之外的其他元素
    list.tail
    //新增元素
    7::list
    //注意,::运算符是从右向左的
    
    //获取前n个元素
    list.take(n)
    //list的zip操作
    val list1 = List(a,b,c)
    list.zip(list1)
    //得到的结果为List((1,a),(2,b),(3,c)),如果两个list的长度不同,以比较短的为基础
    
    //flatten操作
    val list2 = List(List(1,2),List(2,3),List(3,4))
    list2.flatten
    //得到的结果为List(1,2,2,3,3,4),用于将嵌套List组合成一个新的List
    
    //flatmap操作
    list2.flatmap(_.map(_ * 2))
    //跟flatten相比,flatmap在组合之前,会先对每个子List进行map操作

    case class和模式匹配:

    case class又称为样例类,和普通的类相比,样例类不用new就可以实例化,默认执行的是apply方法来构造对象

    模式匹配:

    和其他语言的switch功能差不多,但是Scala里面使用的是match
    使用示例:

    val res = 1
    res match{
        case 0 => println(0)
        case 1 => println(1)
        case 2 => println(2)
    }

    除了用法格式上略有不同,其余的基本类似,并且不需要使用break关键字

    样例类和模式匹配结合使用:

    //定义抽象类Human
    abstract class Human
    //分别定义用例类Chinese,Japanese,American都继承自Human
    case class Chinese(name:String) extends Human
    case class Japanese(name:String) extends Human
    case class American(name:String) extends Human
    
    //定义模式匹配方法
    def caseMatch(human:Human){
        //human参数类型不同,做出不同处理,Chinese(_)表示只关心是不是Chinese而不关心叫什么名字
        case Chinese(_) => println("Chinese")
        case Japanese(_) => println("Japanese")
        case American(_) => println("American")
    }
  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/jchubby/p/5449395.html
Copyright © 2011-2022 走看看