【大数据开发】scala——模式匹配(类型匹配、数组匹配、列表匹配、元组匹配、样例匹配、option类型)、高阶函数(闭包、柯里化、偏函数、高阶函数和模式匹配的结合)、隐式转换和隐式函数、泛型

一、模式匹配

1.1结构和概念

match case的语法如下:变量 match { case 值 => 代码 }如果值为下划线,则代表了不满⾜以上所有情况下的默认情况如何处理。此外,match case中,只要⼀个case分⽀满⾜并处理了,就不会继续判断下⼀个case分⽀了。(与Java不同,java的switch case需要⽤break阻⽌)

(1)使⽤|分割多个选项(表示“或”)
(2)可以给模式添加守卫

/**
 * 与switch-case不同的地方
 *      1. 模式匹配中,没有穿透性
 *      2. 在case后面,可以使用|连接多个值,表示“或”的意思
 *      3. 在模式匹配的最后,使用_来表示上述都不成立的情况
 *      4. 可以给匹配项添加if守卫
 */
object _01_matchTest1 {
    // 模式匹配的基础应用
    def main(args: Array[String]): Unit = {

        val oper = StdIn.readLine("请输入一个操作符")
        val x = 10
        val y = 20

        // 值匹配
        oper match {
            case "+" => println(x + y)
            case "-" => println(x - y)
            case "*" | "x" => println(x * y)
            case "/" => println(x / y)

            case _ if oper.length > 1 => println("操作符的位数不对啊")
            case _ => println("其他的操作符")
        }
    }
}

1.2类型匹配

Scala的模式匹配⼀个强⼤之处就在于,可以直接匹配类型,⽽不是值!!!这点是java的switch case绝对做不到的。
注意: 当你在匹配类型的时候,必须给出⼀个变量名,否则你将会拿对象本身来进⾏匹配

(1)如果只想要进行类型的匹配,不想要这个变量或者对该变量进行向下转型,那么可以使用_下划线进行占位

(2)Float 匹配类型为Class的Float对象

object _02_matchTest2 {
    def main(args: Array[String]): Unit = {
        // 类型匹配: 比switch-case更强大
        val array: Array[Any] = Array(123, "hello", 'a', 3.14f, true)
        val element = array(Random.nextInt(array.length))

        // 逻辑:
        // 如果element实际的类型,和case之后的类型匹配上,就会将值给前面的变量进行赋值,并且执行=>之后的逻辑
        // 如果指向进行类型的匹配,不想向下转型,给匹配变量赋值,可以使用_表示占位
        element match {
            case x: Int => println(s"匹配到了一个整数 $x")
            case x: String => println(s"匹配到了一个字符串 $x")
            case _: Char => println("匹配到了一个字符")
            case _: Double => println("匹配到了一个浮点型")
            case Float => println("匹配到了一个Float类型") // 类型为 Class的Float对象

            case _ => println(s"出现了其他的类型 $element")
        }
    }
}

1.3数组匹配

对Array进⾏模式匹配,分别可以匹配带有指定元素的数组带有指定个数元素的数组以某元素打头的数组

1.4列表匹配

1.5元组匹配

object _03_matchTest3 {
    def main(args: Array[String]): Unit = {
        // 数组匹配
        val array = Array(0, 1, 2)

        array match {
            case Array(0) => println("逐个元素的匹配,这里表示数组中只有0")
            case Array(x, y) => println(s"匹配两个元素的数组,将值分别给x和y赋值 x = $x, y = $y")
            case Array(0, _*) => println("匹配任意的以0开头的数组")
            case _ => println("没有包含0的数组")
        }

        // 列表匹配
        val list = List(0, 1, 2)
        list match {
            case 0 :: Nil => println("逐个元素的匹配,这里表示列表中只有0")
            case x :: y :: Nil => println(s"匹配两个元素的列表,将值分别给x和y赋值 x = $x, y = $y")
            case 0 :: tail => println("匹配任意的以0开头的列表")

            case _ => println("匹配到了其他的列表")
        }

        // 元组匹配
        var tuple = (3.14, 100)
        tuple match {
            case (3.14, 100) => println("具体的值匹配")
            case (x, y) => println(s"匹配到两个元素的元组, x = $x, y = $y")
            case (x, _) => println(s"匹配到连个元素的元组, x = $x, y的值我不在乎")
            case (3.14, y) => println(s"匹配到两个元素的元组, x是3.14, y = $y")
            case (x, 100) =>
        }
    }
}

1.6样例类匹配

实质是样例类的拆分模式

这里的类的匹配,匹配成功后,可以将属性给指定的变量进行赋值(这一切都依赖于unapply()方法,这里为了方便直接写的是case class,因为case class内部提供了unapply方法)

向下转型可以转换为模式匹配,看IDEA提示

/**
 * 这里的类的匹配, 匹配成功后, 可以将属性给指定的变量进行赋值
 * 这一切,都依赖一个方法 unapply
 */
object _04_matchTest4 {
    def main(args: Array[String]): Unit = {
        val student = Student("xiaobai", 10, "male")
        student match {
            case Student(name, age, gender) => println(s"$name, $age, $gender")
            case Student(name, age, _) => println(s"$name, $age")
        }
    }

    def showAnimalProperties(animal: Animal): Unit = {
        animal match {
            case Dog(name, age) =>
                println(s"匹配到了一个Dog对象, name = $name, age = $age")
            case Cat(name, age, _) =>
                println(s"匹配到了一个Cat对象, name = $name, age = $age")
            case Rabbit(name, _, hobby) =>
                println(s"匹配到了一个Rabbit对象, name = $name, hobby = $hobby")
        }
    }
}

case class Student(name: String, age: Int, gender: String)

abstract class Animal
case class Dog(name: String, age: Int) extends Animal
case class Cat(name: String, age: Int, furColor: String) extends Animal
case class Rabbit(name: String, age: Int, hobby: String) extends Animal

1.7Option类型

在Scala中Option类型样例类⽤来表示可能存在或也可能不存在的值(Option的⼦类有Some和None)。
Some包装了某个值,None表示没有值。
Option表示可能存在,也可能不存在值

对于Option类型的值,不要直接使用get()方法获取值,这是因为很可能拿到一个none值,我们可以使用模式匹配拿出来(另外一种方法是:map.getOrElse()方法)

object _05_matchTest5 {
    def main(args: Array[String]): Unit = {
        // Option表示可能存在,也可能不存在的值
        // 有两个子类 Some, None

        val map = Map("u1s1" -> "有一说一")
        map.get("u1s1") match {
            case Some(x) => println(x)
            case None => println("没有值")
        }

        val value = map.get("u1s1") match {
            case Some(x) => x
            case None => "defaultValue"
        }
        println(value)
    }
}

二、高阶函数

(1)传入参数为函数
(2)传入参数为匿名函数
(3)传⼊参数为⽅法(隐式转换⽅法到函数)

2.1高阶函数初体验

object _01_functionTest1 {
    def main(args: Array[String]): Unit = {
        val calculate: (Int, Int) => Int = _ + _
        // 1. 直接使用
        println(calculate(10, 20))
        // 2. 存入一个变量
        val cal2 = calculate
        println(cal2(10, 20))
        // 3. 作为参数
        // 传入三个参数,其中第一个参数是函数,返回一个Int型的值
        val calculator: ((Int, Int) => Int, Int, Int) => Int = _(_, _)
        println(calculator(calculate, 10, 20))
		// 相当于_*_(10,20),前面的是一个函数,后面括号内传入参数
        println(calculator(_-_, 10, 20))
        // 4. 作为返回值
        val calculator2: Boolean => ((Int, Int) => Int) = x => {
            if (x) {
                (a: Int, b: Int) => a + b
            } else {
                (a: Int, b: Int) => a - b
            }
        }
        calculator2(true)(10, 20)
    }
}

2.2闭包

object _02_functionTest2 {
    def main(args: Array[String]): Unit = {

        val x = 10

        // 闭包1: 使用到了外部的一个局部变量,返回值依赖这个局部变量
        val calculator1: () => Int = () => x * 2

        //
        val calculator2: Int => Int = _ + x

        val test1: () => Unit = test()
        test1()

    }

    def test(): () => Unit = {
        val a = 10
        () => println(a)
    }
}

2.3柯里化

/**
 * 函数的柯里化 curring
 */
object _03_functionTest3 {
    def main(args: Array[String]): Unit = {
        calculateFakeCurring(10)(20)
        println(calculateCurring(10)(20))

        calculateCurring(10)_
    }
    // 非柯里化的写法
    def calculate(x: Int, y: Int): Int = x + y

    // 非柯里化的写法
    def calculateFakeCurring(x: Int): Int => Int = {
        (y: Int) => x + y
    }

    // 柯里化的写法
    def calculateCurring(x: Int)(y: Int): Int = x + y
}

2.4偏函数

/**
 * 偏函数
 */
object _04_functionTest4 {
    def main(args: Array[String]): Unit = {
        val res0: Int = test.apply("abc")
        println(res0)

        println(test.apply("one"))
        println(test.apply("two"))
        println(test.isDefinedAt("four"))       // 判断是否定义了与指定的case相匹配的计算逻辑

        // 偏函数,在调用apply的时候,是可以省略不写的
        println(test("one"))
    }

    // 1. 定义一个偏函数
    def test: PartialFunction[String, Int] = {
        case "one" => 1
        case "two" => 2
        case "three" => 3

        case _ => -1
    }
}

2.5 高阶函数和模式匹配的结合

object _05_functionTest5 {
    // 高阶函数和模式匹配的结合
    def main(args: Array[String]): Unit = {
        showNum(1)
        showNum("123")
        showNum(3.14)

        val shower: Any => Unit = {
            case t: Int => println(s"Int => $t")
            case t: String => println(s"String => $t")
            case _ => println("other")
        }
        shower(1)
        shower("123")
        shower(3.14)

        val array: Array[Any] = Array(1, 2, 3, 4, "hello")
        // 需求: 对这个数组中,所有的数字+1,其他类型的不变
        val res0: Array[Any] = array.map({
            case a: Int => a + 1
            case x: Any => x
        })
        println(res0.mkString(", "))
    }

    def showNum(number: Any): Unit = {
        number match {
            case x: Int => println(s"Int => $x")
            case x: String => println(s"String => $x")
            case _ => println("other")
        }
    }
}

三、隐式转换和隐式函数

3.1隐式类

使用关键字implicit修饰的类就是隐式类,是对某一个已经存在的类的增强,是为了给某一个可扩展功能的
在定义隐式类的时候,需要在主构造器中,定义出需要增强的类类型的参数

隐式类定义在object中

注意事项:
1.隐式转换类书写的位置要求:只能定义在class、trait、object中
2.隐式类中的主构造器只能有一个非隐式参数
3.隐式类不能是case class
4.使用的位置:如果时候用到的隐式转换类不在当前的上下文定义,需要导入包

object _01_implictTest1 {

    def main(args: Array[String]): Unit = {
        val a: String = "hello"
        a.printLength()

        1.compare(2)
        1.compareTo(2)
    }

    implicit class StringExtension(source: String) {
        def printLength(): Unit = println(source.length)
    }
}

/**
 * 隐式类:
 * 使用关键字 implicit 修饰的类就是隐式类, 是对某一个已经存在的类的增强, 是为了给某一个类拓展功能的
 * 在定义隐式类的时候,需要在主构造器中,定义出需要增强的类类型的参数
 *
 * 注意事项:
 *  1. 隐式类,只能定义在class、trait、object中
 *  2. 隐式类的主构造器,只能有一个非隐式参数
 *  3. 隐式类不能是case class
 *  4. 使用的时候,如果使用到的隐式转换类不在当前的上下文定义,需要导包
 *      导入指定的隐式转换类
 *          import day05._03_implict._02_implictTest2.StringExtension
 *      导入指定类中所有的隐式转换类
 *          import day05._03_implict._02_implictTest2._
 */
object _02_implictTest2 {
    implicit class StringExtension(source: String) {
        def printLength(): Unit = println(source.length)
        def concat(other: String*): String = source + ", " + other.mkString(", ")
    }
    implicit class IntExtension(source: Int)
    implicit class FloatExtension(source: Float)
}

object Test2 {
    def main(args: Array[String]): Unit = {
        // 1. 定义一个字符串
        val str = "hello"
        // 2. 使用隐式类中增强的方法
        // 如果隐式类不在当前的类中定义,使用的时候,需要导入
        // 导入指定的隐式转换类
        // import day05._03_implict._02_implictTest2.StringExtension
        // 导入指定类中所有的隐式转换类
        import day05._03_implict._02_implictTest2._
        str.printLength()
        println(str.concat("world", "你好", "师姐"))
    }
}

3.2隐式方法

使用关键字implict修饰方法,就是隐式方法
一般情况下,是实现一个类型到另一个类型的隐式转换

字符串类型的数字不能转换成Int类型,这是因为没有从String到Int的隐式转换方法
那么我们可以自定义一个方法

当需要从String转型到Int的时候,会从当前上下文中查找是否有指定的转型的方法

1.在一个上下文中,不能同时出现两个相同的类型转换方法
2.当隐式转换方法不在需要使用的方法中(方法中包含这个隐式方法)时,我们这个时候需要导入这个类

/**
 * 隐式方法: 使用关键字 implicit 修饰的方法,就是隐式方法
 * 一般情况下,是实现一个类型到另外一个类型的隐式转换
 *
 * 1. 在一个上下文中,不能同时出现两个相同的类型转换方法
 */
object _03_implicitTest3 {
    def main(args: Array[String]): Unit = {
        // 当需要从String转型为Int的时候,会从当前上下文中查找是否有指定的转型的方法

        // 定义了一个隐式转换的方法,可以由String转型为Int
        val num1: Int = "1234"
        val num2: Int = false
        val num3: Boolean = 1

        println(num1)
        println(num2)
        println(num3)
    }
    implicit def string2int(str: String): Int = Integer.parseInt(str)
    implicit def boolean2int(bl: Boolean): Int = if (bl) 1 else 0
    implicit def int2boolean(value: Int): Boolean = value != 0
}

3.3隐式参数

1.使用implict修饰的参数,就是隐式参数
2.隐式参数在调用的时候,可以给值,也可以不给值
3.使用隐式参数前提条件:在调用隐式参数的时候,如果不给隐式参数赋值,那么会从当前上下文中查找隐式变量
4.不能出现多个相同类型的隐式变量,否则在使用的时候会因为不确定使用哪一个而出错。但是可以有多不同类型的隐式变量


/**
 * 隐式参数
 */
object _04_implicitTest4 {

    def main(args: Array[String]): Unit = {

        // 前提条件:
        // 当前的上下文中,需要有一个隐式变量
        implicit val a: Int = 10

        // 不能出现多个隐式变量,否则在使用的时候会因为不确定使用哪一个而出错
        // implicit val b: Int = 100
        implicit val b: String = "123"

        // 在调用隐式参数的方法的时候,如果不给隐式参数赋值,那么会从当前上下文中查找隐式变量
        // 直接作为这个方法的参数
        println(calculate(10))
        println(calculate(10)(20))
    }

    // 使用implicit修饰的参数,就是隐式参数
    // 隐式参数,在调用的时候,可以给值,也可以不给值
    def calculate(x: Int)(implicit y: Int): Int = x + y
}

四、泛型

[B <: A] upper bounds 上限或上界:B类型的上界是A类型,也就是B类型的⽗类是A类型
[B >: A] lower bounds 下限或下界:B类型的下界是A类型,也就是B类型的⼦类是A类型
[B <% A] view bounds 视界:(过时了)表示B类型要转换为A类型,需要⼀个隐式转换函数
[B : A] context bounds 上下⽂界定(⽤到了隐式参数的语法糖):需要⼀个隐式转换的值
[-A]:逆变,作为参数类型。是指实现的参数类型是接⼝定义的参数类型的⽗类
[+B]:协变,作为返回类型。是指返回类型是接⼝定义返回类型的⼦类

object _01_genericTest1 {
    def main(args: Array[String]): Unit = {
        // val value: PetContainer[Dog] = new PetContainer[Dog](new Dog)
        // val res0: PetContainer[Pet] = value
        // new PetContainer[Dog].print(new Dog())

        val values: PetContainer2[Hashiqi] = new PetContainer2[Dog]()
    }
}

class Pet
class Dog extends Pet
class Hashiqi extends Dog

// 泛型上界 [A <: Pet] : 表示泛型A的类型,可以是Pet或者Pet的子类型
// 泛型下界 [A >: Dog] : 表示泛型A的类型,可以是Dog或者Dog的父类型
class PetContainer[+A]() {
    // 泛型定义为协变时,在成员中不能直接使用这个泛型
    // def printPetInfo(pet: A): Unit = println(pet)
    // 如果需要在成员方法中使用,成员方法也需要添加泛型
    def printPetInto[B >: A](pet: B): Unit = println(pet)
}

class PetContainer2[-A]() {
    // 泛型定义为逆变时,在成员中可以直接使用
    def printPetInfo(pet: A): Unit = println(pet)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值