Scala 的隐式转换

隐式转换:编译器 偷偷地,自动地帮我们把一种数据类型转换为另一种类型。
         例如:Int --> Double
它有失败的时候(Double --> Int),有成功的时候
当它转换失败的时候,我们提供一个工具,让它能成功

object test {


  //明确地,把Double转成Int
  implicit def X(d:Double):Int = {

    println("implicit X 被调用了")
    d.toInt
  }

  def main(args: Array[String]): Unit = {
    var i:Int = 1
    i = 2.1 //把Double 转入 Int.正常会报错
//    j = i  // 把Int    转入 Double
    println(i)
  }
}

内部流程如下图所示:

f50ca3b220394d2a85e4c69893d955f4.jpeg

需求:
完成一个功能,让所有的字符串都能调用isPhone方法,来校验自己是不是一个手机号

object test1 {
  //开始你的代码
  class StrongString(val str:String){
    def isPhone(): Boolean = {
      val reg = "1[3-9]\\d{9}".r
      reg.matches(str)
    }
  }

  //定义一个特殊的转换函数,把str ==> StrongString的对象
  def tranform(str:String):StrongString = {
    new StrongString(str)
  }

  implicit def stringToStrongString(str: String): StrongString = {
    new StrongString(str)
  }

  def main(args: Array[String]): Unit = {
    val str = "13612345678"
//    println(isPhone(str))
//    println(isPhone("abc"))
//    println((new StrongString(str)).isPhone())
    println( tranform("abc").isPhone() )
    println(str.isPhone()) // ==> true
    println("136a".isPhone()) // ==> false
  }
}

2.函数的隐式参数
一直在修改原来的代码!!!
困难:函数有一个默认数值,在不传入具体的实参时,就会自动使用这个默认值。
难点在于,这个默认值不能修改!

object test {
  //函数参数的默认值
  def sayName(implicit name:String = "小明"): Unit = {
    println("我的名字是:" + name)
  }

  //隐式值
  implicit val value:String = "小张"

  def main(args: Array[String]): Unit = {
    sayName("小王")
    sayName()
    sayName
  }
}

 结果如下:

babeda21f9954e94848d6705486f92ee.png

3.隐式类
任务:给之前是BaseUser添加新的功能,但是,不要直接去改代码
思路:把BaseUser 通过隐式转换,改成一个新类型,而是这个新类型中有这新的方法
implicit class ===  一个隐式转换函数 + 类
它的作用:拓展已有类的功能,而不需要去修改之前的类的代码

object test2 {
  implicit class PowerUser(b:BaseUser) {
    def updateUser() {println("updateUser")}
  }

//  def xxxxxx(b:BaseUser) : PowerUser = {
//    new PowerUser()
//  }
  // 10 年,小王写的代码
  class BaseUser{
    def showUser(): Unit = {
      println("showUser")
    }
  }

  def main(args: Array[String]): Unit = {
    val u1 = new BaseUser()
    u1.showUser()

//    transform(u1).updateUser() //希望要增加新的功能
    u1.updateUser() //希望要增加新的功能
  }
}

结果如下:

aace30afd6624431a08ae09d612f4708.png

 任务:给整数添加一个功能,求阶乘

相关代码如下:

import scala.language.postfixOps
// 需求:给整数添加一个功能,求阶乘
// 5! = 1*2*3*4*5 = 120
object test3 {

  implicit class xxxxx(d:Int) {
    def ! :Int = {
      println("阶乘函数被调用", d)
      // 写代码,完成1*2*3*...*d
      var rs = 1
      for (i <- 1 to d ){
        rs *= i
      }
      rs
    }
  }

  def main(args: Array[String]): Unit = {
    println(5.!)
    println(6!)
  }
}

 结果如下:

 0f674827f1de4c8f91e61693be7ca199.png

作用域:1.代码写在包对象

               2.代码写在一个单独文件,要用的时候就导入

 代码写在包对象时的情况如下:

//包对象中
package object test39 {
  implicit class xxxxx(d: Int) {
    def ! : Int = {
      println("阶乘函数被调用", d)
      // 写代码,完成1*2*3*...*d
      var rs = 1
      for (i <- 1 to d) {
        rs *= i
      }
      rs
    }
  }
}

在同一个包(package test39)中可直接调用

package test39
object test4 {
  def main(args: Array[String]): Unit = {
    println(5.!)
  }
}

代码写在一个单独文件,要用的时候就导入时的情况如下:

//在单独文件中写
object pub {
  implicit class xxxxx(d: Int) {
    def ! : Int = {
      println("阶乘函数被调用", d)
      // 写代码,完成1*2*3*...*d
      var rs = 1
      for (i <- 1 to d) {
        rs *= i
      }
      rs
    }
  }
}

使用时要调用该文件:

import pub._ //调用该文件
class test_39 {
  def main(args: Array[String]): Unit = {
    println(5.!)
  }
}

4.隐式对象

4.1隐式对象的定义  

  隐式对象是一个带有implicit关键字的单例对象,它可以用于提供某种类型的实例以供隐式转换使用。隐式对象通常用于将某个类或trait的实例隐式地注入到方法中。

//隐式对象
//implicit object
//作用:给函数的隐式参数提供默认值
object test5 {
  case class DatabaseConfig(driver: String, url:String)

  implicit object MySqlDefault extends DatabaseConfig("mysql","localhost:443")

  def getConn(implicit config: DatabaseConfig): Unit = {
    println(config)
  }

  def main(args: Array[String]): Unit = {
//    getConn.DatabaseConfig("sqlite","localhost:80")
    getConn
  }
}

 隐式对象和前面讲的隐式参数比较类似,都是用来设置初始数据的。

### Scala 转换机制及其应用 在 Scala 中,转换是一种强大的特性,允许编译器自动将一种类型的对象转换为另一种类型。这种功能通过 `implicit` 关键字来实现。 #### 定义转换函数 转换可以通过定义带有 `implicit` 关键字的方法来完成。当遇到无法匹配参数类型的调用时,编译器会尝试查找适用的转换方法并应用它[^1]。 ```scala // 定义一个简单的转换函数 implicit def intToString(x: Int): String = x.toString ``` 上述代码定义了一个从 `Int` 到 `String` 的转换,在需要字符串的地方可以无缝使用整数变量而无需显的 `.toString()` 转换操作。 #### 使用上下文中的值 除了定义转换规则外,还可以利用已导入的作用域内的值来进行更复杂的逻辑处理或提供默认参数设置[^2]。 ```scala object MathUtil { implicit val defaultPrecision: Double = 0.0001 def approxEquals(a: Double, b: Double)(implicit precision: Double): Boolean = math.abs(a - b) <= precision } ``` 在这个例子中,如果未指定精度,则采用预设好的值作为比较的标准误差范围。 #### 应用于库设计模 Lift Web Framework 就很好地运用了这一概念,比如其 CSS 绑定机制就依赖于视图绑定支持动态页面元素更新而不必每次都手动传递模板片段[^3]。 ```scala class MySnippet { def render = "#someElement *" #> "Hello world" } ``` 这里展示了如何借助 CSS 选择器语法简化 HTML 片段替换过程,并且背后依靠的就是框架内部定义的一系列转换规则使得开发者能够写出更加直观简洁的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值