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")
    }
  • 相关阅读:
    [转] JS报 “尚未实现” 错误
    分享到国内各SNS网站的代码
    IE8以下版本不支持动态创建的HTML5元素?
    一个较为个性化的出生日期选择
    关于拖拽上传 [一个拖拽上传修改头像的流程]
    用CSS写出漂亮的小三角
    用户自定义模块的实现方案
    纪录一则IE的bug
    onpropertychange 和 oninput
    判断脚本加载完毕
  • 原文地址:https://www.cnblogs.com/jchubby/p/5449395.html
Copyright © 2011-2022 走看看