zoukankan      html  css  js  c++  java
  • Scala函数式编程

    <title>Scala编程</title>

    一、Scala函数式编程

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

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

    一行:

    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
    }
    }
    }
  • 相关阅读:
    CF1109F Sasha and Algorithm of Silence's Sounds LCT、线段树
    Solution -「CF 757F」Team Rocket Rises Again
    Solution -「ZJOI2012」「洛谷 P2597」灾难
    Solution -「CF 156D」Clues
    「矩阵树定理」学习笔记
    Solution -「JSOI2008」「洛谷 P4208」最小生成树计数
    Solution -「SHOI2016」「洛谷 P4336」黑暗前的幻想乡
    Solution -「Code+#2」「洛谷 P4033」白金元首与独舞
    Solution -「HDU 5498」Tree
    呐~「多项式」全家桶
  • 原文地址:https://www.cnblogs.com/hsiehchou/p/10670147.html
Copyright © 2011-2022 走看看