大数据技术入门学习(2)Scala入门
沉沙 2018-10-08 来源 : 阅读 1337 评论 0

摘要:本篇教程探讨了大数据技术入门学习(2)Scala入门,希望阅读本篇文章以后大家有所收获,帮助大家对大数据技术的理解更加深入。

本篇教程探讨了大数据技术入门学习(2)Scala入门,希望阅读本篇文章以后大家有所收获,帮助大家对大数据技术的理解更加深入。

<

Scala 简介

它是一门基于JVM的面向函数和面向对象的编程语言, 它包含了求值表达式,闭包,切片操作,模式匹配,隐式转换等特性。

    可变量/不可变量
    可变集合/不可变集合、集合操作
    函数
    值函数
    求值表达式
    函数柯里化
    偏部分应用函数
    偏函数
    闭包
    类(封装、继承、多态)
    特质
    单例类
    伴生单例
    模式匹配(_, * , reg)
    隐匿转换

Scala 安装

环境
服务器:ubuntu-16.04.3-desktop-amd64.iso
我们将要安装的Scala版本是2.10.7, 确保你本地以及安装了Java 8 JDK 版本,并且设置了 JAVA_HOME 环境变量及 JDK 的bin目录。
安装JDK

Ubuntu 16.04安装Java JDK
Java JDK有两个版本,一个开源版本Openjdk,还有一个oracle官方版本jdk。下面记录在Ubuntu 16.04上安装Java JDK的步骤。
安装openjdk
更新软件包列表:

sudo apt-get update

安装openjdk-8-jdk:

sudo apt-get install openjdk-8-jdk

查看java版本:

java -version

直接安装Scala

下载地址https://downloads.lightbend.com/scala/2.10.7/scala-2.10.7.tgz, 并将其解压缩到指定位置:

sudo mkdir /usr/local/scala    # 创建一个根目录
sudo tar -zxf scala-2.10.7.tgz -C /usr/local/scala  # 解压缩到指定位置

    (可选)下载scala集成开发环境
    我这里是下载IntelliJ IDEA >社区版本,https://www.jetbrains.com/idea/download 下载后解压缩包,在bin文件夹下运行./idea.sh启动,然后在引导页面选择添加Scala支持

添加scala到环境变量

打~/.bashrc文件,在尾部添加如下内容

export SCALA_HOME=/usr/local/scala/scala-2.10.7
export PATH=${SCALA_HOME}/bin:$PATH

然后使环境变量生效

source ~/.bashrc

检查scala是否安装成功

scala -version

结果如图所示:
简单使用

进入命令解释窗口:
scala 变量
不可变变量 val

val pi = 3.14

可变变量 var

在scala中一切皆对象,即使数字都有方法。

var name = "John"
name = "rose"
var age = 30  # 但是没有age++这种写法

2.to(5)    # res3: ...Inclusive = Range(2, 3, 4, 5)
1.+(1)     # 1+1 = 2, 

可变与不可变集合的对应关系
不可变集合

不可变集合一旦被创建,便不能改变;添加,删除,修改元素操作返回的是新集合。
默认就是不可变集合scala.collection.immutable包。

val arr = Array[Int](10,20)
val arr1 = arr :+ 1  #  返回一个追加了元素的新集合, 这里:表示原集合,+表示附加操作
val arr1 = 1 :+ arr  #  返回一个追加了元素的新集合, 这里:表示原集合,+表示附加操作
val arr1 = arr ++ arr  #  ++ 表示连接

可变集合

可以添加,删除,修改元素作用于原集合
如果要使用可变集合import scala.collection.mutable

val arr = mutable.ArrayBuffer[Int](10,20)
arr += 10   # 添加元素
val mutableSet = mutable.Set(1,2,3)

定长数组

数组的长度在定义时已经确定, 在运行时长度不能被修改。能过new来进行默认初始化

val numArr = new Array[Int](10)
val strArr = new Array[String](10)

变长数组

变长数组在程序运行过程中, 数组的长度是可以进行调整的,最常用的变长数组是ArrayBuffer, 使用它前必需显示的引用包 import scala.collection.mutable._ 如下所示:

import scala.collection.mutable._
val strArr = ArrayBuffer[String]()
strArr += "hello"  # 追加一个对象
# 用++= 来追加一个集合
strArr ++= Array("Welcome", "to", "china")
strArr.trimEnd(2)  # 删除末尾2个对象
# 遍历数组
for (i <- 0 until strArr.length) println(i)
# 常用函数
strArr.min
strArr.max
strArr.toString
strArr.mkString

列表List

val liststr = List("Spark", "Hive", "Flink")
val liststr = "Spark" ::( "Hive" :: Nil)  # 也可以用如下方式进行创建
# 常用函数有:
liststr.isEmpty
liststr.head
liststr.tail
liststr.reverse
# 连接两个List
 List("hello") ::: List("Boys" , "and", "Girls")
# 丢弃前n个元素
liststr.drop(1)
# zip操作
val nums = List(1,2,3)
val chars = List('1','2','3')
val z = nums zip chars #结果为z: List[(Int, Char)] = List((1,1), (2,2), (3,3))
# 伴生对像方法 
List.range(2,6)  # 构建某一值范围内的List
List.range(2,6,2) # 加上步长参数
List.make(5, "boy") # 构建多个相同元素的List
List.unzip(z)    # unzip 前面的z不变量

函数

scala对象的构造可以使用apply函数, 而不需要new操作, 以下两行是等价的:

val arr = Array(1,2,3,4)  
val arr = Array.apply(1,2,3,4)  

表达式

在scala表达式的是有结果的

var age = 30
val result = if (age >= 18) "adult" else "child"
val result = if (age >= 18) {1|2|3}  # 最后一语句的值就是整个表达式的值
for (i <- 0 to 10 if i%2 == 0) {print(i)} # 产生集合 <- 是生成器generator 
for (i <- 0 until (10,2)) {print(i)} # until 不右包含, 步长为2
var x = for (i <- 0 until (10,2)) yeild i # 缓存结果i成一个vector集合
import scala.util.control.Breaks._  #SCALA 没有break, 要引入Break对像
for (i <- 0 to 10) {if (i == 4) break ; print(i)} # 产生集合,输出,

Scala 函数

Scala 函数声明格式如下, 方括号为可选

    def functionName ([参数列表]) : [return type]

Scala 函数定义格式如下:

    def functionName ([参数列表]) : [return type] = {
    function body
    return [expr] # 最后一句可以省略return 作为返回值
    }

例子如下:

    def printMe( ) : Unit = {
    println("Hello, Scala!")
    }

    def sum(numbers : Int*) = {
    var result = 0;
    for (elem <- numbers) result += elem;
    result
    }

Scala 值函数 (函数字面量 or 函数变量 or 函数指针)

Scala 值函数, 本质上它是一个量指向一段计算代码,定义格式如下:

    val literalName = ([参数列表]) > {
    body
    expr # 作为结果值
    }

它没有返回类, 而是一个映射, 通过=> 符号将左边类型转到右边类型。如果只有一行是{}可以省略; 形如(x:Int,y:Int)=>{x+y}的表达式称为Lambda表达式。
将值函数(函数变量)作为另一个函数的输入参数:

val increment=(x:Int)=>x+1
val arrInt = Array(1,2,3,4)
arrInt.map(increment) # 这是map就是高阶函数,即参数或者返回值含有值函数
# 其它高阶函数
arrInt.flatMap # 将集合中各元素得到一个集合,并扁平合并成一个集合
arrInt.reduce  # 使用2元操作在一个集合上,返回一个值
arrInt.filter  # 返回满足条件的集合值
arrInt.fold    # 带有初始值的reduce

闭包 (Closure)

John D.Cook 给对象和闭包下过一个经典的定义:"An object is data with function. A closure is a function with data", 由此闭包是由函数和运行时数据决定的。 事实上, 闭包可以理解为函数和它的上下文, 例如:

var i = 15
val f=(x:Int)=>x+i
f(10)    # 结果是25

函数柯里化(currying)(就是括号化, 很多多括号)

在前面所述, 当高价函数返回的是一个函数对象是, 就可能会存在fun(1)(2)这种调用方式, 那么如果显示声明这样一个形式的函数,也就是函数柯里化, 它的定义形式如下:

def curryFunctionName (param_x:Int)(param_y:Int)(param_z:Int):Int = {
}

实例如下:

def mul(x:Int)(y:Int):Int={x * y}

由此可见, 调用柯里化函数时, 参数必须要示完整。所以它不具备传部分参数,然后返回某个对象的能力。
部分应用函数

为了应对柯里化函数对完整参数的限制, 提出部分应用函数, 即先输入部分参数, 调用返回一个中间对象, 然后通过中间对象进行后续调用, 使得柯里化+部分应用函数类似高阶函数的表现形式:

# 生成一个部分应用函数
val paf = mul(10) _
# 调用部分应用函数
paf(5)    # 结果为50

不只柯里化函数有部分应用函数, 普通函数也有部分函数, 例如:

def product (x1:Int, x2:Int, x3:Int) = x1 * x2 * x3
val paf = product(_:Int, 2, 3)
paf(2)   # 结果12

偏函数

它是数学函数上的,自变量与因变量, 当在值域找不到对应目标时,就报错。

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

示例如下:

val isEven : PartialFunction[Int, String] = {
    case x if x % 2 == 0 => x + "is even"
}
isEven(10)  # 这个OK
isEven(11)  # 这里报错

Scala 下划线

    1、存在性类型:Existential types
    def foo(l: List[Option[_]]) = ...

    2、高阶类型参数:Higher kinded type parameters
    case class AK[_],T

    3、临时变量:Ignored variables
    val _ = 5

    4、临时参数:Ignored parameters
    List(1, 2, 3) foreach { _ => println("Hi") }

    5、通配模式:Wildcard patterns
    Some(5) match { case Some() => println("Yes") }
    match {
    case List(1,,) => " a list with three element and the first >element is 1"
    case List(*) => " a list with zero or more elements "
    case Map[,] => " matches a map with any key type and any value >type "
    case _ =>
    }
    val (a, ) = (1, 2)
    for ( <- 1 to 10)

    6、通配导入:Wildcard imports
    import java.util._

    7、隐藏导入:Hiding imports
    // Imports all the members of the object Fun but renames Foo to Bar
    import com.test.Fun.{ Foo => Bar , _ }

    // Imports all the members except Foo. To exclude a member rename it to >
    import com.test.Fun.{ Foo => , _ }

    8、连接字母和标点符号:Joining letters to punctuation
    def bang_!(x: Int) = 5

    9、占位符语法:Placeholder syntax
    List(1, 2, 3) map (_ + 2)
    _ + _
    ( (: Int) + (: Int) )(2,3)

    val nums = List(1,2,3,4,5,6,7,8,9,10)

    nums map (_ + 2)
    nums sortWith(>)
    nums filter (_ % 2 == 0)
    nums reduceLeft(+)
    nums reduce (_ + )
    nums reduceLeft( max )
    nums.exists( > 5)
    nums.takeWhile(_ < 8)

    10、偏应用函数:Partially applied functions
    def fun = {
    // Some code
    }
    val funLike = fun _

    List(1, 2, 3) foreach println _

    1 to 5 map (10 * _)

    //List("foo", "bar", "baz").map(_.toUpperCase())
    List("foo", "bar", "baz").map(n => n.toUpperCase())

    11、初始化默认值:default value
    var i: Int = _

    12、作为参数名:
    //访问map
    var m3 = Map((1,100), (2,200))
    for(e<-m3) println(e._1 + ": " + e._2)
    m3 filter (e=>e._1>1)
    m3 filterKeys (_>1)
    m3.map(e=>(e._1*10, e._2))
    m3 map (e=>e._2)

    //访问元组:tuple getters
    (1,2)._2

    13、参数序列:parameters Sequence
    _*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理。例如val s = >sum(1 to 5:_*)就是将1 to 5当作参数序列处理。
    //Range转换为List
    List(1 to 5:_*)

    //Range转换为Vector
    Vector(1 to 5: _*)

    //可变参数中
    def capitalizeAll(args: String*) = {
    args.map { arg =>
    arg.capitalize
    }
    }

    val arr = Array("what's", "up", "doc?")
    capitalizeAll(arr: _*)

Scala 面向对象编程
类的定义

Scalal中的类与Java语言一样通过class来定义:

import scala.beans.BeanProperty   // 如果使用BeanProperty需要引入

class Person{
    // 成员变量必须初始化, 这里会生成scala的getter与setter
    var name:String = null  // getter就是name, setter就是name_
    @BeanProperty var age:Int = 0 //这里会生成Java风格的setAge(),getAge()
    
}

类成员访问

val p = new Person
p.name_= ("John")  // 显示调用setter方法修改成员变量, 这里是_= () 方法
p.name = "John"    // 直接修改成员变量name, 实际也是调用p.name_= 方法
p.setAge(1)
p.getAge()

主构造函数

为了简化构造函数与类定义, scala 提供了主构造函数,集定义与构造于一身:

// 注意有个var关键字
class Person(var name:String, var age:Int) //这就完成了上述声明与构造。
class Person(var name:String, var age:Int=18)//这样就带默认参数了

辅助构造函数

为了实现多个构造函数,且不带默认参数的, 提出辅助构造函数。连带好处还避免多处使用类名字的问题, 就是使用this关键字:

class Person{
    private age:Int = 18
    private name:String = null
    def this(name:String){  # 这里就是辅助构造函数
        this()              # 调用无参的默认主构造函数
        this.name = name
    }
    def this(name:String,age:Int){
        this(name)
        this.age = age
    }
}

继承 和 多态

# 注意新添加字段有var关键, 继承的没有,构造时为传递参数值
class Student(name:String, age:Int, var studentNo:String) extends Person(name,age){
 override def toString:String = super.toString + ", studentNo=" + studentNo
}
var p = new Person("bill")
p = new Student("John", 33, "12345")
p.toString

注: 如果类或者trait声明前加sealed 关键字,则其所有派生都必须放在同一个文件中
默认访问控制(隐藏)

    public : 是默认选项, 类,伴生单例,子类, 外部都可以访问
    protected : 类,伴生单例,子类可以访问,外部不可以访问
    private : 类,伴生单例可以访问,子类,外部不可以访问
    private[this]: 类可以访问,伴生单例,子类,外部不可以访问

访问控制符,还可以放在主构造函数中,起到相信的效果:

// 这里name的控制符是protected,而age就是默认的控制符 public
class Person(protected var name:String, var age:Int) 
// 如果在主构造函数中, 未使用val ,var关键字来定义字段,就是默认为private[this]
class Person(name:String, age:Int)

抽象类

就是用abstract来定义类, 抽象类可以拥有抽象成员,即不初始化成员

abstract class Person{
  var age:Int = 0   // 具体成员
  var name:String   // 抽象成员
  def walk()        // 抽象成员
  override def toString = name // 具体成员
}

单例对象(类)

在java中经常会用到静态成员变量, 但是在Scala没有并不支持这项特性, 取而代之的是单例对象, 它是通过object 来声明的, 示例如下:

object GlobalID { var gid:Int = 0 }
GlobalID.gid

伴生对象与伴生类

就是名字相同的类与单例对象,可以相互访问私有成员。它们分别叫做伴生类与伴生对象(单例)。 类似C++的friend关系

class Dog {
  private var name = "张"

  def printName(): Unit = { //在Dog类中访问其伴生对象的私有属性
    (Dog.CONSTART + name)
  }
}

object Dog {
  private val CONSTART = "汪"
  def main(args: Array[String]): Unit = {
    val p = new Dog
    println(p.name)
    p.name = "大黄"
    p.printName()
  }
}

trait 特质

Scala用trait关键字封装了成员方法和成员变量, 在类通过extends或with关键字来混入trait。一个类可以混入多个trait。
它起到了interface接口的作用,以及struct结构嵌入的作用等。
它的定义示例如下:

// 可克隆特质
trait Closable{
  def close():Unit
}

// 通过extends 来实现特质
class File(var name:String) extends Closable{
  def close():Unit = println(s"File $name has been closed")
}
// 也可以如下
class File(var name:String) extends java.io.File(name) with Closable{
  def close():Unit = println(s"File $name has been closed")
}
// 在trait类似抽象类, 在trait中可以有抽象成员, 成员方法, 具体成员和具体方法。
trait PersonDAO{
// 具体成员变量
var recordNum:Long = _
// 具体成员方法
def add(p:Person):Unit={
  println("Invoking add Method..")
}
// 抽象方法 更新方法
def update(p:Person)
// 抽象方法 删除方法
def delete (id:Int)
}

注意, 使用trait出现菱形继承问题时, 使用的是最右深度优先遍历算法查找调用的方法。
提前定义与懒加载

提前定义是指在常规构造之前将变量初始化, 下述的构造会出现空指针。

class FileLogger{
var fileName : String
val fileOutput = new PrintWriter(fileName:String)
def log(msg:String) : Unit = {
  fileOutput.print(msg)
  fileOutput.flush()
}
}

// 正常构造使用,就会报错
val s = new {
  // 提前定义
  override val fileName = "file.log"
} with FileLogger
s.log("predefined variable")

懒加载, 上述提前定义的方式不够优雅, 推荐使用下面的懒加载方式

class FileLogger{
var fileName : String
// 这里的语句的不会执行,只等真正使用该变量时才会执行
lazy val fileOutput = new PrintWriter(fileName:String)
def log(msg:String) : Unit = {
  fileOutput.print(msg)
  fileOutput.flush()
}
}

val s = new FileLogger
s.fileName = "file.log"
s.log("predefined variable")

模式匹配

匹配是一个以match关键连接的简单表达式, 结果为match匹配的执行结果

// 1.简单匹配
val (first, second) = (1,2)
// 2.常量匹配
for (i <- 1 to 5){
 i match{
  // 常量匹配
  case 1 => println(1)
  // 3.变量匹配
  case x if (x%2 == 0) => println(s"Mode 2 equal zero")
  case _ => printlen("other")
 }
}
// 4.case类匹配
case class Dog(val name:String, val age:Int)   // 以case关键字定义开始
case class Person(var name:String, var age:Int) 
case class Student(var name:String, var age:Int) 
def myMatch(x:AnyRef) = x match{
  // 4.1case类构造匹配
  case Dog(name, age) => println(s"Dog name=$name, age=$age")
  // 4.2case类类型匹配
  case x:Person => pringln(s"this is a person")
  // 4.3case类变量匹配
  case s@Student(_,_) => println(s"Student:" + s)
  case _ => println("other")
}
val dog = new Dog("jacky", 11)
val p = new Person("Peter", 22)
val std = new Student("Jim", 33)
myMatch(dog)
myMatch(p)
myMatch(std)
// 5.序列模式

def myMatch(x:AnyRef) = x match{
  // 序列模式
  case Array(first,second) => println(s"first:$first, second:$second")
  case Array(first,_,third,_*) => println(s"first:$first, third:$third")
  // 6.元组模式
  case (first,second) => println(s"tuple first:$first, second:$second")
  case (first,_, third) => println(s"tuple first:$first, third:$third")
  case _ =>
}
val arr = Array(1,2,3,4)
myMatch(arr)
val arr = Array(1,2)
myMatch(arr)
val tuple = ("nest",1)
myMatch(tuple)

正则表达式

val rgex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r  // .r 将字符串转化正则表达式
// 以下是几个常用方法
for (date <- rgex.findAllIn("2015-12-31 2016-02-30")) println(date)
for (date <- rgex findAllMatchIn "2015-12-31 2016-02-30") println(date.groupCount)

for 中的模式匹配

// 常量匹配
for ((name, 18)<-Map("jack"->22, "tom"->18, "ben"->7)) println(name)
// 变量匹配
for ((name,age)<-Map("jack"->22, "tom"->18, "ben"->7)) println(name,age)
// 变量绑定
for ((name, e@7)<-Map("jack"->22, "tom"->18, "ben"->7)) println(name,e)
// 类型匹配
for ((name, age:Int)<-Map("jack"->22, "tom"->18, "ben"->7)) println(name,age)
// 构造匹配
// 序列匹配

隐式转换

隐式转换函数 - 将参数类型转换为返回类型

// 隐式转换函数的定义
// 它是通过参数类型与返回类型确定的
// 因而不能有这样的两个函数,它们参数与返回值类型都相同
implicit def int2float(x:Int):Float = x.toFloat 

隐式转换类 - 将参数类型转换为隐式类类名类型

// 这就是把字符串类型转换为Dog类
implicit class Dog(val name:String)

应用程序对象

object MyApp {
 def main(args:Array[String]){
    println("App v1")
 }
}

   

本文由职坐标整理发布,学习更多的大数据技术相关知识,请关注职坐标大技术云计算大技术技术频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程