这篇短文将结合实例对隐式转换的各种场景进行解释和总结,希望看完的人能够安全驶过隐式转换这个大坑。

隐式转换函数

隐式转换函数有两种作用场景。

  • 1 转换为期望类型:就是指一旦编译器看到X,但需要Y,就会检查从X到Y的隐式转换函数。
  • 2 转换方法的调用者:简单来说,如obj.f(),如果obj对象没有f方法,则尝试将obj转换为拥有f方法的类型。
object ImpFunction extends App { class Dog(val name: String) { def bark(): Unit = println(s"$name say: Wang !") } implicit def double2int(d: Double): Int = d.toInt implicit def string2Dog(s: String): Dog = new Dog(s) val f: Int = 1.1 //转换为期望类型,1.1通过double2int转成了Int类型 println(f) "Teddy".bark() // 转换方法的调用者,字符串通过string2Dog转成了Dog, 于是有了bark方法}// output// 1// Teddy say: Wang !

val f: Int = 1.1 因为类型不匹配,这段本来是无法通过编译的,但是编译器发现存在一个Double至Int的隐式转换函数,所以进行了隐式转换。

"Teddy".bark() String类型本来是没有bark方法的,但是编译器发现了隐式转换string2Dog可以使得String转成一种拥有bark方法的类型,相当于进行了这样的转换:string2Dog("Teddy").bark()。

注意事项

需要注意的是,编译器只关心隐式转换函数的输入输出类型,不关心函数名,为避免歧义,同一个作用域中不能有输入输出类型相同的两个隐式转换函数,不然编译器会报错。

隐式类

Scala 2.10引入了一种叫做隐式类的新特性。隐式类指的是用implicit关键字修饰的类。使用情况与隐式转换函数类似,可以看做将类的构造函数定义为隐式转换函数,返回类型就是这个类。

package io.github.liam8.implobject ImpClass extends App { implicit class Dog(val name: String) { def bark(): Unit = println(s"$name say: Wang !") } "Teddy".bark()}

注意事项

这段来自官网https://docs.scala-lang.org/zh-cn/overviews/core/implicit-classes.html隐式类有以下限制条件:

  • 1 只能在别的trait/类/对象内部定义。
 object Helpers { implicit class RichInt(x: Int) // 正确! } implicit class RichDouble(x: Double) // 错误!
  • 2 构造函数只能携带一个非隐式参数。
 implicit class RichDate(date: java.util.Date) // 正确! implicit class Indexer[T](collecton: Seq[T], index: Int) // 错误! implicit class Indexer[T](collecton: Seq[T])(implicit index: Index) // 正确!

虽然我们可以创建带有多个非隐式参数的隐式类,但这些类无法用于隐式转换。

  • 3 在同一作用域内,不能有任何方法、成员或对象与隐式类同名。
  • 注意:这意味着隐式类不能是case class。
 object Bar implicit class Bar(x: Int) // 错误! val x = 5 implicit class x(y: Int) // 错误! implicit case class Baz(x: Int) // 错误!

隐式参数 & 隐式值

package io.github.liam8.implobject ImpParam extends App { def bark(implicit name: String): Unit = println(s"$name say: Wang !") implicit val t: String = "Hot Dog" bark}

参数加上implicit就成了隐式参数,需要与隐式值(变量定义加上implicit)搭配使用,最后一行的bark缺少了一个String类型的参数,编译器找到了String类型的隐式值,便将其传入,相当于执行了bark(t)。

implicit关键字会作用于函数列表中的的所有参数,如def test(implicit x:Int, y: Double)这样定义函数,x和y就都成了隐式函数。但是通常我们只希望部分参数为隐式参数,就好比通常会给部分参数提供默认值而不是全部都指定默认值,于是隐式参数常常与柯里化函数一起使用,这样可以使得只有最后一个参数为隐式参数,例如def test(x: Int)(implicit y: Double)。

是完整的例子。

object ImpParamWithCurry extends App { def bark(name: String)(implicit word: String): Unit = println(s"$name say: $word !") implicit val w: String = "Wang" bark("Hot Dog")}

注意事项

下面这段来自https://blog.csdn.net/m0_37138008/article/details/78120210

  • 1)当函数没有柯里化时,implicit关键字会作用于函数列表中的的所有参数。
  • 2)隐式参数使用时要么全部不指定,要么全不指定,不能只指定部分。
  • 3)同类型的隐式值只能在作用域内出现一次,即不能在同一个作用域中定义多个相同类型的隐式值。
  • 4)在指定隐式参数时,implicit 关键字只能出现在参数开头。
  • 5)如果想要实现参数的部分隐式参数,只能使用函数的柯里化,
  • 如要实现这种形式的函数,def test(x:Int, implicit y: Double)的形式,必须使用柯里化实现:def test(x: Int)(implicit y: Double).
  • 6)柯里化的函数, implicit 关键字只能作用于最后一个参数。否则,不合法。
  • 7)implicit 关键字在隐式参数中只能出现一次,柯里化的函数也不例外!

隐式对象

类似于隐式值, 要结合隐式参数使用。先看一个栗子(下面的代码需要认真体会)。

package io.github.liam8.implobject ImpObject extends App { //定义一个`排序器`接口,能够比较两个相同类型的值的大小 trait Ordering[T] { //如果xy返回1,x==y则返回0. def compare(x: T, y: T): Int } //实现一个Int类型的排序器 implicit object IntOrdering extends Ordering[Int] { override def compare(x: Int, y: Int): Int = { if (x < y) -1 else if (x == y) 0 else 1 } } //实现一个String类型的排序器 implicit object StringOrdering extends Ordering[String] { override def compare(x: String, y: String): Int = x.compareTo(y) } //一个通用的max函数 def max[T](x: T, y: T)(implicit ord: Ordering[T]): T = { if (ord.compare(x, y) >= 0) x else y } println(max(1, 2)) println(max("a

无法将类型int隐式转换为string_Scala implicit 隐式转换安全驾驶指南相关推荐

  1. 【Unity】Unity C#基础(十五)implicit 隐式类型转换、explicit 显式类型转换

    文章目录 implicit 隐式类型转换 Explicit 显式类型转换 总结 implicit 隐式类型转换 implicit关键字用于声明隐式的用户自定义的类型转换运算符. 如果可以确保转换过程不 ...

  2. c#中无法将类型“int”隐式转换为“System.IntPtr”

    问: c#中无法将类型"int"隐式转换为"System.IntPtr" 这个是我引用了一个api函数时出现的问题,我在声明中把intptr换成了int还是不可 ...

  3. 006永磁电机永磁体的类型:何为凸极性、隐极性,表贴式、内置式,傻瓜式讲解,专为零基础编写。

    从电机的命名上大家也可以看出来, 之所以叫永磁电机, 是因为该电机的的转子上是永磁体, 不同于其他电机通过线圈通电产生磁场产生转动力矩. 永磁体在转子上的不同布置, 会导致内部磁场的特性有所不同, 常 ...

  4. 可空类型int? 解决: 【数据库里的int类型可以为null,而在c#里int类型不能为Nul】的问题

    using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace 可空数据类 ...

  5. Scala篇—implicit隐式入门

    Scala篇-implicit隐式入门 一.implicit概述 1.简介 2.为什么需要implicit 3.隐式转换机制 4.隐式转换规则 5.使用implicit须知 二.Demo示例 1.隐式 ...

  6. java整数类型int字面值_JavaKotlinAndroidGuide

    Java是一种强类型化的语言,每个变量都有一种类型,每个表达式也都有一种类型,并且每一种类型都是严格定义的.所有的赋值操作不管是显式的还是在方法中调用中通过参数传递的,都要经过类型兼容性检查 一.基本 ...

  7. scala 隐式详解(implicit关键字)

    掌握implicit的用法是阅读spark源码的基础,也是学习scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...

  8. 正规式转换为NFA代码实现

    问题引入 正规式是一种编译原理课程中经常提到的描述文法的语法规则,与正则表达式有相同之处,但并不是同一个概念.有效的正规式的字母表∑ = { a − z , A − Z } . 所有的正规式中的符号以 ...

  9. VB2010 的隐式续行(Implicit Line Continuation)

    VB2010 的隐式续行(Implicit Line Continuation) 许多情况下,您可以让 VB 后一行继续前一行的语句,而不必使用下划线(_).下面列举出隐式续行语法的使用情形. 1.逗 ...

最新文章

  1. maven java jar_在maven中引入本地jar包的方法
  2. Redirecting to /bin/systemctl restart sshd.service
  3. redhat6.下安装配置hadoop环境--单实例版本
  4. matlab simulink笔记05 —— 积分模块
  5. Django 的第三方包
  6. 部署Django工程
  7. python敏感词替换
  8. JobTracker作业启动过程分析
  9. Camera ISP
  10. emWin BATTON控件透明化
  11. [Ynoi2015]此时此刻的光辉
  12. 2021-2027全球与中国IPA干燥机市场现状及未来发展趋势
  13. torch.nn.Embedding的函数
  14. 伊美尔在港招股书失效:首次冲刺上市折戟,曾多次遭到处罚
  15. js:ajax post与get的区别,getjson的使用
  16. ⚡性能优化之首屏秒开
  17. android动态mac地址,Android 版本兼容 — Android 6.0 和 7.0后获取Mac地址
  18. ubuntu桌面出现问题,重启x桌面方法
  19. 编译安装nginx实现反向代理、负载均衡、缓存功能
  20. 使用canvas画一个流星动画送给她吧

热门文章

  1. 天鼎:一个技术人在世界读书日的遐想
  2. 【JEECG技术文档】online自定义模板的使用
  3. UI标签库专题二:JEECG智能开发平台Column(列) 子标签
  4. Python中的_main_与_init_详解
  5. Linux信号实践(4) --可靠信号
  6. 怎样改动SharePoint管理中心的语言
  7. Flask-第二课:路由
  8. CentOS 6.5安装使用docker
  9. Centos6.4 编译安装 nginx php
  10. PE下如何安装 安装版系统