Scala编程

一、Scala函数式编程

多范式:面向对象,函数式编程(程序实现起来简单)

举例:WordCount
sc 是 SparkContext , 非常重要

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

一行:


  
   var result = sc.textFile(
   "hdfs://xxxx/xxx/data.txt") 
  
  
   .flatMap(
   _.
   split(
   " ")).
   map((
   _,
   1)).reduceByKey(
   _+
   _).collect 
  

1、复习函数

关键字 def

2、匿名函数

没有名字的函数
举例:


  
   scala> 
   var myarray = 
   Array(
   1,
   2,
   3) 
  
  
   myarray: 
   Array[
   Int] = 
   Array(
   1, 
   2, 
   3) 
  
  
    
  
  
   scala> def fun1(x:
   Int):
   Int = x*
   3 
  
  
   fun1: (x: 
   Int)
   Int 
  
  
    
  
  
   scala> (x:
   Int) => x*
   3 
  
  
   res0: 
   Int => 
   Int = <function1> 
  
  
    
  
  
   问题:怎么去调用?高阶函数 
  
  
   scala> fun1(
   3) 
  
  
   res1: 
   Int = 
   9 
  
  
    
  
  
   scala> myarray.
   foreach(println) 
  
  
   1 
  
  
   2 
  
  
   3 
  
  
    
  
  
   //调用匿名函数 
  
  
   scala> myarray.map((x:
   Int) => x*
   3) 
  
  
   res3: 
   Array[
   Int] = 
   Array(
   3, 
   6, 
   9) 
  
  
    
  
  
   (_,
   1) (_+_) 都是匿名函数 
  

3、高阶函数(带有函数参数的函数)

把一个函数作为另外一个函数的参数值

定义一个高阶函数:
对10做某种运算


  
   scala> def someAction(f:(
   Double)=>(
   Double)) = f(
   10) 
  
  
   someAction: (f: 
   Double => 
   Double)
   Double 
  

解释:
(Double)=>(Double) 代表了f 的类型:入参是double,返回值也是double的函数


  
   import scala.math._ 
  
  
    
  
  
   scala> someAction(
   sqrt) 
  
  
   res5: 
   Double = 
   3.1622776601683795 
  
  
    
  
  
   scala> someAction(
   sin) 
  
  
   res6: 
   Double = -
   0.5440211108893698 
  
  
    
  
  
   scala> someAction(
   cos) 
  
  
   res7: 
   Double = -
   0.8390715290764524 
  
  
    
  
  
   scala> someAction(println) 
  
  
   <console>:
   16: error: 
   type mismatch; 
  
  
   found : () => 
   Unit 
  
  
   required: 
   Double => 
   Double 
  
  
    someAction(println) 
  
  
    ^ 
  
  
   def someAction(f:(
   Double)=>(
   Double)) = f(
   10) 
  
  
    
  
  
   someAction(
   sqrt) = 
   sqrt(
   10) 
  

4、高阶函数的实例

scala中提供了常用的高阶函数

(1)map : 相当于一个循环,对某个集合中的每个元素都进行操作(接收一个函数),返回一个新的集合

scala> var numbers = List(1,2,3,4,5,6,7,8,9,10)
numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> numbers.map((i:Int)=>i*2)
res2: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

scala> numers.map(_*2)
res3: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

说明:
(i:Int)=>i*2 与 _*2 等价的


  
   (
   i
   :Int,j
   :Int)=>i+j _+_ 
  

scala> numbers
res4: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
不改变numbers本身的值

(2)foreach:相当于一个循环,对某个集合中的每个元素都进行操作(接收一个函数),不返回结果
scala> numbers.foreach(println)
1
2
3
4
5
6
7
8
9
10

numbers.foreach(_*2)
没有返回值

(3) filter :过滤,选择满足的数据
举例:查询能被2整除的数字

scala> numbers.filter((i:Int)=>i%2==0)
res5: List[Int] = List(2, 4, 6, 8, 10)

filter函数,参数要求:要求一个返回 bool 值的函数,筛选出所有为true的数据

(4)zip操作:合并两个集合
scala> List(1,2,3).zip(List(4,5,6))
res6: List[(Int, Int)] = List((1,4), (2,5), (3,6))

//少的话匹配不上就不合并
scala> List(1,2,3).zip(List(4,5))
res7: List[(Int, Int)] = List((1,4), (2,5))

scala> List(1).zip(List(4,5))
res8: List[(Int, Int)] = List((1,4))

(5)partition : 根据断言(就是某个条件,匿名函数)的结果,来进行分区
举例:
能被2整除的分成一个区,不能被2整除的分成另外一个区
scala> numbers.partition((i:Int)=>i%2==0)
res9: (List[Int], List[Int]) = (List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))

(6)find : 查找第一个满足条件的元素
scala> numbers.find(_%3==0)
res10: Option[Int] = Some(3)

_%3==0 (i:Int)=>i%3==0 一样

(7)flatten:把嵌套的结果展开
scala> List(List(2,4,6,8,10),List(1,3,5,7,9)).flatten
res11: List[Int] = List(2, 4, 6, 8, 10, 1, 3, 5, 7, 9)

(8)flatmap : 相当于一个 map + flatten
scala> var myList = List(List(2,4,6,8,10),List(1,3,5,7,9))
myList: List[List[Int]] = List(List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9))

scala> myList.flatMap(x=>x.map(_*2))
res22: List[Int] = List(4, 8, 12, 16, 20, 2, 6, 10, 14, 18)

myList.flatMap(x=>x.map(_*2))

执行过程:
1、将 List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9) 调用 map(_*2) 方法。x 代表一个List
2、flatten


  
   package day4 
  
  
    
  
  
   /** 
  
  
    * 对比flatmap与map 
  
  
    */ 
  
  
   object Demo2 { 
  
  
    
  
   
   /** 
  
  
    * flatmap执行分析 
  
  
    * 1 List(1*2) List(2) 
  
  
    * 2 List(2*2) List(4) 
  
  
    * 3 List('a','b') 
  
  
    * 
  
  
    * List(List(2),List(4),List('a','b')).flatten 
  
  
    * List(2,4,'a','b') 
  
  
    */ 
  
  
    def flatMap(){ 
  
  
    val li = 
   List(
   1,
   2,
   3) 
  
  
    val res = li.flatMap(x=> 
  
  
    x match{ 
  
   
   case 
   3=>
   List(
   'a',
   'b') 
  
   
   case _=>
   List(x*
   2) 
  
  
    }) 
  
  
    println(res) 
  
  
    } 
  
  
    
  
   
   /** 
  
  
    * map过程解析 
  
  
    *  
  
  
    * 1 2 ---->List(2,2,3) 
  
  
    * 2 4 ---->List(2,4,5) 
  
  
    * 3 List('a','b')---->List(2,4,List('a','b')) 
  
  
    */ 
  
  
    def map(){ 
  
  
    val li = 
   List(
   1,
   2,
   3) 
  
  
    val res = li.map(x=> 
  
  
    x match{ 
  
   
   case 
   3=>
   List(
   'a',
   'b') 
  
   
   case _=>x*
   2 
  
  
    }) 
  
  
    println(res) 
  
  
    } 
  
  
    
  
  
    def main(args: Array[
   String]): Unit = { 
  
  
    flatMap() 
  
  
    map() 
  
  
    } 
  
  
   } 
  

5、概念:闭包、柯里化

(1)闭包:就是函数的嵌套
在一个函数的里面,包含了另一个函数的定义
可以在内函数中访问外函数的变量

举例:


  
   def mulBy(factor:Double) = 
   (x:Double)=>x*factor 
  
  
    外 内 
  

乘以三:


  
   scala> def mulBy(factor:
   Double) = (x:
   Double)=>x*factor 
  
  
   mulBy: (factor: 
   Double)
   Double => 
   Double 
  
  
    
  
  
   scala> 
   var triple = mulBy(
   3) 
  
  
   triple: 
   Double => 
   Double = <function1> 
  
  
    
  
  
   相当于 triple(x:
   Double) = x*
   3 
  
  
    
  
  
   scala> triple(
   10) 
  
  
   res1: 
   Double = 
   30.0 
  
  
    
  
  
   scala> triple(
   20) 
  
  
   res2: 
   Double = 
   60.0 
  
  
    
  
  
   scala> 
   var half = mulBy(
   0.5) 
  
  
   half: 
   Double => 
   Double = <function1> 
  
  
    
  
  
   scala> half(
   10) 
  
  
   res3: 
   Double = 
   5.0 
  

引入柯里化:
scala> mulBy(3)(10)
res4: Double = 30.0

(2)柯里化
概念:柯里化函数:是把具有多个参数的函数,转化为一个函数链,每个节点上都是单一函数

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

def add(x:Int)(y:Int) = x+y

转化步骤:

原始:def add(x:Int,y:Int) = x+y

闭包:def add(x:Int) = (y:Int) => x+y

简写:def add(x:Int)(y:Int) = x+y

scala> def add(x:Int)(y:Int) = x+y
add: (x: Int)(y: Int)Int

scala> add(1)(2)
res5: Int = 3

二、Scala集合

1、可变集合和不可变集合(Map)

immutable mutable
举例:
scala> def math = scala.collection.immutable.Map(“Tom”->80,”Lily”->20)
math: scala.collection.immutable.Map[String,Int]

scala> def math = scala.collection.mutable.Map(“Tom”->80,”Lily”->20,”Mike”->95)
math: scala.collection.mutable.Map[String,Int]

集合的操作:
获取集合中的值
scala> math.get(“Tom”)
res1: Option[Int] = Some(80)

scala> math(“Tom”)
res2: Int = 80

scala> math(“Tom123”)
java.util.NoSuchElementException: key not found: Tom123
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
… 32 elided

scala> math.get(“Tom123”)
res3: Option[Int] = None

scala> math.contains(“Tom123”)
res4: Boolean = false

scala> math.getOrElse(“Tom123”,-1)
res5: Int = -1

更新集合中的值:注意:必须是可变集合
scala> math
res6: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

scala> math(“Tom”)=0
scala> math
res7: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

造成上述现象的原因,没有import包,如果import以后,问题解决:
scala> import scala.collection.mutable._
import scala.collection.mutable._

scala> var math = Map(“Tom”->80,”Lily”->20,”Mike”->95)
math: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

scala> math(“Tom”)=0
scala> math
res8: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 0, Lily -> 20)

添加新的元素
scala> math(“Tom”)=80
scala> math += “Bob”->85
res9: scala.collection.mutable.Map[String,Int] = Map(Bob -> 85, Mike -> 95, Tom -> 80, Lily -> 20)

移出一个元素
scala> math -= “Bob”
res10: scala.collection.mutable.Map[String,Int] = Map(Mike -> 95, Tom -> 80, Lily -> 20)

2、列表:可变列表,不可变列表

不可变列表 List
scala> var myList=List(1,2,3)
myList: List[Int] = List(1, 2, 3)

scala> val nullList:List[Nothing] = List()
nullList: List[Nothing] = List()

//二维列表
scala> val dim : List[List[Int]] = List(List(1,2,3),List(4,5,6))
dim: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))

scala> myList.head
res11: Int = 1

scala> myList.tail
res12: List[Int] = List(2, 3)

注意:tail 是除了第一个元素外,其他的元素

可变列表:LinedList 在 scala.collection.mutable 包中

scala> var myList = scala.collection.mutable.LinkedList(1,2,3,4)
warning: there was one deprecation warning; re-run with -deprecation for details
myList: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4)

需求:把上面列表中,每一个元素都乘以2

游标,指向列表的开始


  
   var cur = myList 
  
  
   //Nil意思为空 
  
  
   while(cur != Nil ){ 
  
  
    
  
   
   //把当前元素乘以2 
  
  
    cur
   .elem = cur.elem*
   2 
  
  
    
  
   
   //移动指针到下一个元素 
  
  
    cur = cur
   .next 
  
  
   } 
  

scala> var cur = myList
cur: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4)

scala> while(cur != Nil ){
| cur.elem = cur.elem*2
| cur = cur.next
| }

scala> myList
res13: scala.collection.mutable.LinkedList[Int] = LinkedList(2, 4, 6, 8)

scala> myList.map(_*2)
warning: there was one deprecation warning; re-run with -deprecation for details
res14: scala.collection.mutable.LinkedList[Int] = LinkedList(4, 8, 12, 16)

3、序列

(*)数据库中也有序列:sequence 、 auto increment
(1)作为主键,实现自动增长
(2)提高性能,序列在Oracle是在内存中的

(*)Vector Range
举例:
Vector 是一个带下标的序列,我们可以通过下标来访问Vector中的元素
scala> var v = Vector(1,2,3,4,5,6)
v: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5, 6)

Range : 是一个整数的序列
scala> Range(0,5)
res15: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4)

从0开始,到5 ,但不包括5

scala> println(0 until 5)
Range(0, 1, 2, 3, 4)

scala> println(0 to 5)
Range(0, 1, 2, 3, 4, 5)

Range可以相加
scala> (‘0’ to ‘9’) ++ (‘A’ to ‘Z’)
res16: scala.collection.immutable.IndexedSeq[Char] = Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z)

把Range转换成list
scala> 1 to 5 toList
warning: there was one feature warning; re-run with -feature for details
res17: List[Int] = List(1, 2, 3, 4, 5)

4、集(Set)

不重复元素的集合,默认是HashSet,与java类似
scala> var s1 = Set(1,2,10,8)
s1: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

scala> s1 + 10
res18: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

scala> s1 + 7
res19: scala.collection.immutable.Set[Int] = Set(10, 1, 2, 7, 8)

scala> s1
res20: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8)

创建一个可排序的Set SortedSet
scala> var s2 = scala.collection.mutable.SortedSet(1,2,3,10,8)
s2: scala.collection.mutable.SortedSet[Int] = TreeSet(1, 2, 3, 8, 10)

判断元素是否存在
scala> s2.contains(1)
res21: Boolean = true

scala> s2.contains(1231231)
res22: Boolean = false

集的运算:union并集 intersect 交集 diff 差集
scala> var s1 = Set(1,2,3,4,5,6)
s1: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)

scala> var s2 = Set(5,6,7,8,9,10)
s2: scala.collection.immutable.Set[Int] = Set(5, 10, 6, 9, 7, 8)

scala> s1 union s2
res23: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 6, 9, 2, 7, 3, 8, 4)

scala> s1 intersect s2
res24: scala.collection.immutable.Set[Int] = Set(5, 6)

scala> s1 diff s2
res25: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

数据库里面的union操作,要求:
列数一样
列的类型一样


  
   select A,B from **** 
  
  
   union  
  
  
   select C,D from ***** 
  

函数的定义+返回值
def sum():Int =

python数据分析
pyspark

5、模式匹配

相当于java中的switch case语句 但是 功能更强大


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 模式匹配 
  
  
    */ 
  
  
   object Demo1 { 
  
  
    def main(args: 
   Array[String]): Unit = { 
  
   
   //1、相当于java switch case 
  
   
   var chi = 
   '-' 
  
   
   var sign = 
   0 
  
  
    
  
  
    chi match { 
  
   
   case 
   '+' => sign = 
   1 
  
   
   case 
   '-' => sign = 
   -1 
  
   
   case _ => sign = 
   0 
  
  
    } 
  
  
    println(sign) 
  
  
    
  
   
   /** 
  
  
    * 2、scala中的守卫,case _ if 匹配某种类型的所有值 
  
  
    * 需求:匹配所有的数字 
  
  
    */ 
  
   
   var ch2 = 
   '5' 
  
   
   var result : 
   Int = 
   -1 
  
  
    ch2 match { 
  
   
   case 
   '+' => println(
   "这是一个加号") 
  
   
   case 
   '-' => println(
   "这是一个减号") 
  
   
   //这里的10表示转换成1十进制 
  
   
   case _ 
   if Character.isDigit(ch2) => result=Character.digit(ch2,
   10) 
  
   
   case _ => println(
   "其他") 
  
  
    } 
  
  
    println(result) 
  
  
    
  
   
   /** 
  
  
    * 3、在模式匹配中使用变量 
  
  
    * 如果改成var mystr = "Hello W+rld" 
  
  
    * 打印:加号 
  
  
    * 
  
  
    * 匹配中,则相当于break 
  
  
    */ 
  
   
   var mystr = 
   "Hello World" 
  
   
   //取出某个字符,赋给模式匹配的变量 
  
  
    
  
  
    mystr(
   7) match { 
  
   
   case 
   '+' => println(
   "加号") 
  
   
   case 
   '-' => println(
   "减号") 
  
   
   //case 语句中使用变量 ch代表传递进来的字符 
  
   
   case ch => println(ch) 
  
  
    } 
  
  
    
  
   
   /** 
  
  
    * 4、匹配类型 instance of 
  
  
    * 用法:case x : Int => 
  
  
    * 
  
  
    * Any : 表示任何类型,相当于java中的Object 
  
  
    * Unit : 表示没有值, void 
  
  
    * Nothing : 表示在函数抛出异常时,返回值就是Nothing 
  
  
    * 是scala类层级中的最低端,是任何其他类型的子类型 
  
  
    * Null : 表示引用类型的子类,值:null 
  
  
    * 
  
  
    * 特殊类型 
  
  
    * Option : 表示一个值是可选的(有值或者无值) 
  
  
    * Some : 如果值存在,Option[T] 就是一个Some[T] 
  
  
    * None : 如果值不存在,Option[T] 就是一个None 
  
  
    * 
  
  
    * scala> var myMap = Map("Time"->96) 
  
  
    * myMap: scala.collection.immutable.Map[String,Int] = Map(Time -> 96) 
  
  
    * 
  
  
    * scala> myMap.get("Time") 
  
  
    * res0: Option[Int] = Some(96) 
  
  
    * 
  
  
    * scala> myMap.get("Time12342") 
  
  
    * res1: Option[Int] = None 
  
  
    * 
  
  
    * Nil : 空的List 
  
  
    * 
  
  
    * 四个N总结:None Nothing Null Nil 
  
  
    * None : 如果值不存在,Option[T] 就是一个None 
  
  
    * Nothing : 如果方法抛出异常时,则异常的返回值类型就是Nothing 
  
  
    * Null : 可以赋值给所以的引用类型,但是不能赋值给值类型 
  
  
    * class Student 
  
  
    * var s1 = new Student 
  
  
    * s1 = null 
  
  
    * Nil : 空的List 
  
  
    */ 
  
   
   var v4 : Any = 
   100 
  
  
    v4 match { 
  
   
   case x : 
   Int => println(
   "这是一个整数") 
  
   
   case s : String => println(
   "这是一个字符串") 
  
   
   case _ => println(
   "这是其他类型") 
  
  
    } 
  
  
    
  
   
   //5、匹配数组和列表 
  
   
   var myArray = 
   Array(
   1,
   2,
   3) 
  
  
    myArray match { 
  
   
   case 
   Array(
   0) => println(
   "数组中只有一个0") 
  
   
   case 
   Array(x,y) => println(
   "数组中包含两个元素") 
  
   
   case 
   Array(x,y,z) => println(
   "数组中包含三个元素") 
  
   
   case 
   Array(x,_*) => println(
   "这是一个数组,包含多个元素") 
  
  
    } 
  
  
    
  
   
   var myList = 
   List(
   1,
   2,
   3) 
  
  
    myList match { 
  
   
   case 
   List(
   0) => println(
   "列表中只有一个0") 
  
   
   case 
   List(x,y) => println(
   "列表中包含两个元素,和是" + (x+y)) 
  
   
   case 
   List(x,y,z) => println(
   "列表中包含三个元素,和是" + (x+y+z)) 
  
   
   case 
   List(x,_*) => println(
   "列表中包含多个元素,和是" + myList.sum) 
  
  
    } 
  
  
    } 
  
  
   } 
  

6、样本类

定义: case class


  
   package day5 
  
  
   /** 
  
  
    * 使用case class 来实现模式匹配 
  
  
    */ 
  
  
   class Vehicle 
  
  
    
  
  
   case 
   class Car(name:String) extends Vehicle 
  
  
    
  
  
   case 
   class Bike(name:String) extends Vehicle 
  
  
    
  
  
   object Demo2 { 
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   var aCar : 
   Vehicle = 
   new 
   Car(
   "Car") 
  
  
    
  
  
    aCar 
   match { 
  
   
   case 
   Car(name) => println(
   "汽车 " + name) 
  
   
   case 
   Bike(name) => println(
   "自行车 " + name) 
  
   
   case _ => println(
   "其他") 
  
  
    } 
  
  
    } 
  
  
   } 
  

作用:
(1)支持模式匹配,instanceof
(2)定一个 Spark SQL 中的 schema : 表结构


  
   scala> 
   class Fruit 
  
  
   defined 
   class Fruit 
  
  
    
  
  
   scala> 
   class Banana(name:String) extends Fruit 
  
  
   defined 
   class Banana 
  
  
    
  
  
   scala> 
   class Apple(name:String) extends Fruit 
  
  
   defined 
   class Apple 
  
  
    
  
  
   scala> 
   var a = 
   new 
   Apple(
   "Apple") 
  
  
   a: 
   Apple = 
   Apple@
   572e6fd9 
  
  
    
  
  
   scala> println(a.isInstanceOf[
   Fruit]) 
  
  
   true 
  
  
    
  
  
   scala> println(a.isInstanceOf[
   Banana]) 
  
  
   <console>:
   16: warning: fruitless 
   type test: a value of 
   type Apple cannot also be a Banana 
  
  
    println(a.isInstanceOf[
   Banana]) 
  
  
    ^ 
  
  
   false 
  

三、Scala高级特性

1、泛型

和java类似 T

1)泛型类

定义类的时候,可以带有一个泛型的参数
例子:


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 泛型类 
  
  
    */ 
  
  
    
  
  
   //需求:操作一个整数 
  
  
   class GenericClassInt{ 
  
   
   //定义一个整数的变量 
  
   
   private 
   var content : 
   Int = 
   10 
  
  
    
  
   
   //定义set get 
  
  
    def 
   set(value : 
   Int) = content = value 
  
  
    def 
   get() : 
   Int = content 
  
  
   } 
  
  
    
  
  
   //需求:操作一个字符串 
  
  
   class GenericClassString{ 
  
   
   //定义一个空字符串 
  
   
   private 
   var content : 
   String = 
   "" 
  
  
    
  
   
   //定义set get 
  
  
    def 
   set(value : 
   String) = content = value 
  
  
    def 
   get() : 
   String = content 
  
  
   } 
  
  
    
  
  
   class GenericClass[T]{ 
  
   
   //定义变量 
  
   
   //注意:初始值用_来表示 
  
   
   private 
   var content : 
   T = 
   _ 
  
  
    
  
   
   //定义set get 
  
  
    def 
   set(value : 
   T) = content = value 
  
  
    def 
   get() : 
   T = content 
  
  
   } 
  
  
    
  
  
   object Demo3{ 
  
  
    def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //定义一个Int 类型 
  
   
   var v1 = 
   new 
   GenericClass[
   Int] 
  
  
    v1.
   set(
   1000) 
  
  
    println(v1.
   get()) 
  
  
    
  
   
   //定义一个String 类型 
  
   
   var v2 = 
   new 
   GenericClass[
   String] 
  
  
    v2.
   set(
   "Ni") 
  
  
    println(v2.
   get()) 
  
  
    } 
  
  
   } 
  
2)泛型函数

定义一个函数,可以带有一个泛型的参数


  
   scala> def mkIntArray(elem:
   Int*)=
   Array[
   Int](elem:_*) 
  
  
   mkIntArray: (elem: 
   Int*)
   Array[
   Int] 
  
  
    
  
  
   scala> mkIntArray(
   1,
   2,
   3) 
  
  
   res5: 
   Array[
   Int] = 
   Array(
   1, 
   2, 
   3) 
  
  
    
  
  
   scala> mkIntArray(
   1,
   2,
   3,
   4,
   5) 
  
  
   res6: 
   Array[
   Int] = 
   Array(
   1, 
   2, 
   3, 
   4, 
   5) 
  
  
    
  
  
   scala> def mkStringArray(elem:
   String*)=
   Array[
   String](elem:_*) 
  
  
   mkStringArray: (elem: 
   String*)
   Array[
   String] 
  
  
    
  
  
   scala> mkStringArray(
   "a",
   "b") 
  
  
   res7: 
   Array[
   String] = 
   Array(a, b) 
  
  
    
  
  
   scala> def mkArray[T:ClassTag] 
  
  
    
  
  
   ClassTag : 表示scala在运行时候的状态信息,这里表示调用时候数据类型 
  
  
    
  
  
   scala> 
   import scala.reflect.ClassTag 
  
  
   import scala.reflect.ClassTag 
  
  
    
  
  
   scala> def mkArray[T:ClassTag](elem:T*) = 
   Array[T](elem:_*) 
  
  
   mkArray: [T](elem: T*)(implicit evidence$
   1: scala.reflect.ClassTag[T])
   Array[T] 
  
  
    
  
  
   scala> mkArray(
   1,
   2) 
  
  
   res8: 
   Array[
   Int] = 
   Array(
   1, 
   2) 
  
  
    
  
  
   scala> mkArray(
   "Hello",
   "aaa") 
  
  
   res9: 
   Array[
   String] = 
   Array(Hello, aaa) 
  
  
    
  
  
   scala> mkArray(
   "Hello",
   1) 
  
  
   res10: 
   Array[
   Any] = 
   Array(Hello, 
   1) 
  

泛型:但凡有重复的时候,考虑使用泛型

3)上界和下界

Int x
规定x的取值范围 100 <= x <=1000

泛型的取值范围:
T

类的继承关系 A —> B —> C —> D 箭头指向子类

定义T的取值范围 D <: T <: B

T 的 取值范围 就是 B C D

<: 就是上下界的表示方法

概念
上界 S <: T 规定了 S的类型必须是 T的子类或本身
下界 U >: T 规定了 U的类型必须是 T的父类或本身

例子:


  
   package day5 
  
  
   /** 
  
  
    * 主界 
  
  
    */ 
  
  
   //定义父类 
  
  
   class Vehicle{ 
  
   
   //函数:驾驶 
  
   
   def drive() = println(
   "Driving") 
  
  
   } 
  
  
    
  
  
   //定义两个子类 
  
  
   class Car extends Vehicle{ 
  
   
   override 
   def drive() : 
   Unit = println(
   "Car Driving") 
  
  
   } 
  
  
    
  
  
   //class Bike extends Vehicle{ 
  
  
   // override def drive(): Unit = println("Bike Driving") 
  
  
   //} 
  
  
    
  
  
   class Bike{ 
  
   
   def drive(): 
   Unit = println(
   "Bike Driving") 
  
  
   } 
  
  
    
  
  
   object ScalaUpperBoud { 
  
   
   //定义驾驶交通工具的函数 
  
   
   def takeVehicle[
   T <: 
   Vehicle](v:
   T) = v.drive() 
  
  
    
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //定义交通工具 
  
   
   var v : 
   Vehicle = 
   new 
   Vehicle 
  
  
    takeVehicle(v) 
  
  
    
  
   
   var c : 
   Car = 
   new 
   Car 
  
  
    takeVehicle(c) 
  
  
    
  
   
   //因为没有继承Vehicle,所以运行报错 
  
   
   var b : 
   Bike = 
   new 
   Bike 
  
  
    takeVehicle(b) 
  
  
    } 
  
  
   } 
  

  
   scala> def addTwoString[
   T <: String](
   x:T,y:T) = x +" 
   *****
   **** " + y 
  
  
   addTwoString: [
   T <: String](
   x: T, y: T)String 
  
  
    
  
  
   scala> addTwoString("Hello","World") 
  
  
   res11: String = Hello 
   *****
   **** World 
  
  
    
  
  
   scala> addTwoString(1,2) 
  
  
   <console>:14: error: inferred type arguments [Int] do not conform to method addTwoString's type parameter bounds [T 
   <: String] 
  
  
    addTwoString(1,2) 
  
  
    ^ 
  
  
   <console>:14: error: type mismatch; 
  
  
    found : Int(1) 
  
  
    required: T 
  
  
    addTwoString(1,2) 
  
  
    ^ 
  
  
   <console>:14: error: type mismatch; 
  
  
    found : Int(2) 
  
  
    required: T 
  
  
    addTwoString(1,2) 
  
  
    ^ 
  
  
    
  
  
   scala> addTwoString(1.toString,2.toString) 
  
  
   res13: String = 1 
   *****
   **** 2 
  
4)视图界定 View bounds

就是上界和下界的扩展

除了可以接收上界和下界规定的类型以外,还可以接收能够通过隐式转换过去的类型

用 % 来表示


  
   scala> def addTwoString[T <% String](x:T,y:T) = x +
   " ********* " + y 
  
  
   addTwoString: [T](x: T, y: T)(
   implicit evidence$
   1: T => String)String 
  
  
    
  
  
   scala> addTwoString(
   1,
   2) 
  
  
   <console>:
   14: error: No 
   implicit view available from 
   Int => String. 
  
  
    addTwoString(
   1,
   2) 
  
  
    ^ 
  
  
   //定义隐式转换函数 
  
  
   scala> 
   implicit def int2String(n:
   Int):String = n.toString 
  
  
   warning: there was one feature warning; re-run with -feature for details 
  
  
   int2String: (n: 
   Int)String 
  
  
    
  
  
   scala> addTwoString(
   1,
   2) 
  
  
   res14: String = 
   1 ********* 
   2 
  

执行过程:
1、调用了 int2String Int => String
2、addTwoString(“1”,”2”)

5)协变和逆变(概念)

协变:表示在类型参数前面加上 + 。泛型变量的值,可以是本身类型或者其子类类型
例子:


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 协变:表示在类型参数前面加上 + 。泛型变量的值,可以是本身类型或者其子类类型 
  
  
    */ 
  
  
    
  
  
   class Animal 
  
  
    
  
  
   class Bird extends Animal 
  
  
    
  
  
   class Sparrow extends Bird 
  
  
    
  
  
   //定义第四个类,吃东西的类,协变,有继承关系了 
  
  
   class EatSomething[+T](t:T) 
  
  
    
  
  
   object Demo4 { 
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //定义一个鸟吃东西的对象 
  
   
   var c1 : 
   EatSomething[
   Bird] =
   new 
   EatSomething[
   Bird](
   new 
   Bird) 
  
  
    
  
   
   //定义一个动物吃东西的对象 
  
   
   var c2 : 
   EatSomething[
   Animal] = c1 
  
  
    
  
   
   /** 
  
  
    * 问题:能否把c1 赋给c2 
  
  
    * c1 c2都是EatSomething 
  
  
    * c1 c2 没有继承关系 
  
  
    * 
  
  
    * class EatSomething[T](t:T) 
  
  
    * var c2 : EatSomething[Animal] = c1 报错 
  
  
    * 原因 : EatSomething[Bird] 并没有继承EatSomething[Animal] 
  
  
    * 
  
  
    * class EatSomething[+T](t:T) 
  
  
    * 报错消失 
  
  
    * 
  
  
    * 协变 
  
  
    */ 
  
  
    
  
   
   var c3 : 
   EatSomething[
   Sparrow] = 
   new 
   EatSomething[
   Sparrow](
   new 
   Sparrow) 
  
   
   var c4 : 
   EatSomething[
   Animal] = c3 
  
  
    } 
  
  
   } 
  

逆变:表示在类型参数前面加上 - 。泛型变量的值,可以是本身类型或者其父类类型
例子:


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 逆变:表示在类型参数前面加上 - 。泛型变量的值,可以是本身类型或者其父类类型 
  
  
    */ 
  
  
    
  
  
   class Animal 
  
  
    
  
  
   class Bird extends Animal 
  
  
    
  
  
   class Sparrow extends Bird 
  
  
    
  
  
   //定义第四个类,吃东西的类,逆变 
  
  
   class EatSomething[-T](t:T) 
  
  
    
  
  
   object Demo5 { 
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //定义一个鸟吃东西的对象 
  
   
   var c1 : 
   EatSomething[
   Bird] =
   new 
   EatSomething[
   Bird](
   new 
   Bird) 
  
  
    
  
   
   //定义一个动物吃东西的对象 
  
   
   var c2 : 
   EatSomething[
   Sparrow] = c1 
  
  
    } 
  
  
   } 
  

2、隐式转换

1)隐式转换函数: implicit


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 隐式转换 
  
  
    * 
  
  
    * 定义一个隐式转换函数 
  
  
    */ 
  
  
   class Fruit(name:String){ 
  
   
   def getFruitName() : 
   String = name 
  
  
   } 
  
  
    
  
  
   class Monkey(f:Fruit){ 
  
   
   def say() = println(
   "Monkey like " + f.getFruitName()) 
  
  
   } 
  
  
    
  
  
   object ImplicitDemo { 
  
  
    
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //定义一个水果对象 
  
   
   var f : 
   Fruit = 
   new 
   Fruit(
   "Banana") 
  
  
    f.say() 
  
  
    } 
  
  
    
  
   
   implicit 
   def fruit2Monkey(f:
   Fruit) : 
   Monkey = { 
  
   
   new 
   Monkey(f) 
  
  
    } 
  
  
   } 
  

2)隐式参数:使用implicit 修饰的函数参数

定义一个带有隐式参数的函数:


  
   scala> def testPara(
   implicit 
   name:String) = println(
   "The value is " + 
   name) 
  
  
   testPara: (
   implicit 
   name: String)
   Unit 
  
  
    
  
  
   scala> testPara(
   "AAAA") 
  
  
   The 
   value is AAAA 
  
  
    
  
  
   scala> 
   implicit val 
   name : String = 
   "*****" 
  
  
   name: String = ***** 
  
  
    
  
  
   scala> testPara 
  
  
   The 
   value is ***** 
  

定义一个隐式参数,找到两个值中比较小的那个值
100 23 –>23
“Hello” “ABC” –> ABC


  
   scala> def smaller[T](a:T,b:T)(
   implicit order : T => Ordered[T]) = 
   if(a<b) a 
   else b 
  
  
   smaller: [T](a: T, b: T)(
   implicit order: T => Ordered[T])T 
  
  
    
  
  
   scala> smaller(
   1,
   2) 
  
  
   res18: 
   Int = 
   1 
  
  
    
  
  
   scala> smaller(
   "Hello",
   "ABC") 
  
  
   res19: String = ABC 
  

解释:
order 就是一个隐式参数,我们使用Scala中的 Ordered 类,表示该值可以被排序,也就是可以被比较

作用:扩充了属性的功能

3)隐式类 在类名前 加 implicit 关键字
作用:扩充类的功能


  
   package day5 
  
  
    
  
  
   /** 
  
  
    * 隐式类 
  
  
    */ 
  
  
   object Demo6 { 
  
   
   def main(args: 
   Array[
   String]): 
   Unit = { 
  
   
   //执行两个数字的求和 
  
  
    println(
   "两个数字的和是: "+
   1.add(
   2)) 
  
  
    
  
   
   /** 
  
  
    * 定义一个隐式类,类增强1的功能 
  
  
    * 
  
  
    * Calc(x:Int) 
  
  
    * 1是Int类型,所以就会传递进来 
  
  
    * 
  
  
    * 执行过程: 
  
  
    * 1--->Calc类 
  
  
    * var a = new Calc(1) 
  
  
    * 在调用Calc add方法 
  
  
    * a.add(2) 
  
  
    * 
  
  
    */ 
  
   
   implicit 
   class Calc(x:Int){ 
  
   
   def add(y: 
   Int) : 
   Int = x + y 
  
  
    } 
  
  
    } 
  
  
   } 
  
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄