【Scala】 提取器unapply方法

目录

1、apply方法

2、unapply方法

提取器是从传递给它的对象中提取出构造该对象的参数。

Scala 提取器是一个带有unapply方法的对象。unapply方法算是apply方法的反向操作:unapply接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值。

e.g.

传入name = Amy, age = 10,用于构造Student类,

在函数式编程中,val stu = Student(Amy, 10) 创建了stu对象。这个过程中自动执行了apply方法。

val Student (uname, uage) = stu // 自动执行unapply方法,这里接受一个stu对象,然后从stu对象中提取到了构造这个对象时用到的数据。

这里可以得到 uname = Amy, age = 10 


1、apply方法

回顾一下apply,类似构造函数

定义了一个Foo类,并且在这个类中,有一个伴生对象Foo,里面定义了apply方法。有了这个apply方法以后,我们在调用这个Foo类的时候,就可以用函数的方式来调用:

unapply接受一个对象,从对象中提取出相应的值。unapply方法主要用于模式匹配中。

object Client {

    def main(args: Array[String]): Unit = {
        val foo = Foo("Hello")
    }
}

我们用Foo("Hello")的方式,就得到了一个Foo类型的对象,这一切就是apply方法的功劳。如果没有apply方法,我们将需要使用new关键字来得到Foo对象。原来是这样调用的:

class Foo(foo: String) {
}

object Foo {
    def apply(foo: String) : Foo = {
        new Foo(foo)
    }
}

 

2、unapply方法

类似析构函数

unapply方法:根据已经创建好的对象,把它里面的参数提取出来,等于apply的反向操作。

例1

package basic.runoob.advanced


class Money(val value: Double, val country: String) {}

object Money {
  def apply(value: Double, country: String) : Money = new Money(value, country)

  // 提取器
  def unapply(money: Money): Option[(Double, String)] = {
    println("自动调用 unapply")
    if(money == null) {
      None
    } else {
      Some(money.value, money.country)
    }
  }
}

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

    def testUnapply(): Unit = {
      val money = Money(10.1, "RMB") // 自动调用apply
      println("money: " + money.value) // money: 10.1
      money match {
        case Money(num, "RMB") =>  println("RMB: " + num) // 自动调用 unapply
        case _ => println("Not RMB!")
      }
    }

    testUnapply() // RMB: 10.1


  }
}

例2

package basic.runoob.advanced

//  ..../TestUnapply.scala
class Car(val brand:String, val price:Int){
  def info(){
    println("Car brand is "+brand+"and price is "+price)
  }
}

object Car{
  def apply(brand:String, price:Int): Car ={
    println("Debug: calling apply...")
    new Car(brand, price)
  }

  def unapply(c:Car):Option[(String, Int)]={ //返回值是一个Option类型
    println("Debug: calling unapply...")
    Some((c.brand, c.price))
  }
}

object TestUnapply{ //定义入口函数
  def main(args:Array[String]){
    // 根据已经创建好的对象,把它里面的参数提取出来,等于apply的反向操作。
    val Car(carbrand, carprice) = Car("BMW", 800000) //从右往左执行,先执行等号右边,自动调用apply,再执行左边,调用unapply方法
    //右边实例化传入参数生成对象,左右又提取出来,这个在后面做spark编程时会用到这种方式进行模式匹配和提取
    println("brand: " + carbrand + " and carprice:" + carprice)

    println("=" * 10)
    val car1 = Car("aMW", 80)
    car1 match {
        // case Money(num, "RMB") =>  println("RMB: " + num) // 自动调用 unapply
      case Car(carbrand, carprice) =>  println(carprice + " ++++ " + carbrand) // 自动调用 unapply
      case _ => println("Not RMB!")
    }
  }
}

/*
Debug: calling apply...
Debug: calling unapply...
brand: BMW and carprice:800000
==========
Debug: calling apply...
Debug: calling unapply...
80 ++++ aMW
 */

 例3

unapply封装if-else

Scala可以用unapply封装每一个If-else,比如这个

object App {
  def main(args: Array[String]): Unit = {
    val e = "123@456.com"
    if(isEmail(e)){
      println(getPartOne(e))
      println(getPartTwo(e))
    }else{
      println("no an email")
    }
  }
  def isEmail(input:String):Boolean =
    input.split("@").length == 2
  def getPartOne(input:String) =
    input.split("@").apply(0)
  def getPartTwo(input:String) =
    input.split("@").apply(1)
}

可以变成这个

object App {
  def main(args: Array[String]): Unit = {
    "123@456.com" match {
      case Email(a,b) =>
        println(a)
        println(b)
      case _ => println("isn't an email")
    }
  }
}
object Email {
  def unapply(arg: String): Option[(String,String)] = {
    val temp = arg.split("@")
    if(temp.length != 2) None
    else Some((temp(0),temp(1)))
  }
}

 

备注:apply和unapply都是作为伴生对象中的方法,调用类时,自动进行的操作。

  • 构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
  • 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
  • 提供unapply方法使模式匹配可以工作;

 

参考:

scala中的apply方法与unapply方法

SCALA入门实践 - 硕果累累的文章 - 知乎

Scala入门到精通——第二十五节 提取器(Extractor)

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值