Scala隐式转换的问题分析--String隐式转换为Int
Scala隐式转换的问题分析-String隐式转换为Int
引出问题
首先来看一个需求:将String类型的数字赋值给Int类型的变量。
也就是这样:
val num:Int="20"
要想实现这样的效果,小伙伴们应该都能想到使用隐式方法
这个技能。许多小伙伴一鸡冻就撸出了如下的代码:
implicit def strToInt(str:String):Int= {str.toInt}
***友情提示:***隐式转换的代码要定义在object中哦~~~
定义了如上的隐式方法后,接下来我们来使用一下该隐式方法。接下来来一段完整代码尝尝:
object TestDemo {def main(args: Array[String]): Unit = {val num:Int = "20"println(num)}/*** 定义的隐式方法* 该方法的功能是将String转成Int* @param str 需要转换的字符串* @return 返回 Int*/implicit def strToInt(str:String):Int= {str.toInt}}
代码撸完,感觉还不错,接着我们运行以上代码:哐当,出错啦。。。。
控制台输出以下错误信息:
Error:(17, 5) type mismatch;found : str.type (with underlying type String)required: ?{def toInt: ?}
Note that implicit conversions are not applicable because they are ambiguous:both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOpsand method strToInt in object TestDemo of type (str: String)Intare possible conversion functions from str.type to ?{def toInt: ?}str.toInt
Error:(17, 9) value toInt is not a member of Stringstr.toInt
大伙看错误信息中有个关键的单词ambiguous(模糊不清的,模棱两可的)
,以上错误信息的大致意思是说:
隐式转换在这里不适用了,因为隐式转换出现了模糊不清的情况,这里有两个方法
一个在object Predef中有一个augmentString方法将x:String转成scala.collection.immutable.StringOps,
另一个在object TestDemo中有strToInt方法将str: String转成了Int
以上两个方法都可以将str: String转成了Int,所以隐式转换出现了模糊不清的情况
看完后估计有的小伙伴还是一头雾水,这到底是说的啥,这到底是为什么??好,那接下来我们就看看其中的究竟。
分析原因
分析String相关的源码
首先我们来看一段代码:
def main(args: Array[String]): Unit = {val str:String = "20"val i = str.toIntprintln(i)}
以上代码的正确编译运行,输出结果是Int类型的20
。
接下来我们按住键盘上的Ctrl,鼠标点击String查看String类型,发现在object Predef中有这么一段代码:
type String = java.lang.String
通过这段代码我们知道,Scala中的String其实是使用了java中的String。好了,那我们回顾以下java中的String有toInt()方法吗,熟悉Java的肯定立马就能回答:没有。对的,就是没有!!
String中没有toInt()方法,但是这里的str
却可以使用toInt()
,那说明str.toInt
这里发生了隐式转换。没错,这里的str由String转换成了StringOps。这么转换的呢,我们上源码:
implicit def augmentString(x: String): StringOps = new StringOps(x)
在object Perdef中有一个隐式方法augmentString
将String转换成了StringOps。接着我们再来看看StringOps的源码:
final class StringOps(override val repr: String) extends AnyVal with StringLike[String] {override protected[this] def thisCollection: WrappedString = new WrappedString(repr)override protected[this] def toCollection(repr: String): WrappedString = new WrappedString(repr)/** Creates a string builder buffer as builder for this class */override protected[this] def newBuilder = StringBuilder.newBuilderoverride def apply(index: Int): Char = repr charAt indexoverride def slice(from: Int, until: Int): String = {val start = if (from < 0) 0 else fromif (until <= start || start >= repr.length)return ""val end = if (until > length) length else untilrepr.substring(start, end)}override def toString = reproverride def length = repr.lengthdef seq = new WrappedString(repr)
}
在StringOps中没有直接发现toInt()方法,不要慌,仔细看看StringOps
继承了StringLike
,接着我们看看StringLike
源码:
trait StringLike[+Repr] extends Any with scala.collection.IndexedSeqOptimized[Char, Repr] with Ordered[String] {//省略代码................def toInt: Int = java.lang.Integer.parseInt(toString)/*** @throws java.lang.NumberFormatException - If the string does not contain a parsable long.*/def toLong: Long = java.lang.Long.parseLong(toString)}
终于在StringLike中找到了toInt,因为StringOps
继承了StringLike
,所以StringOps
也就有了toInt()。
再看刚才的隐式方法:
implicit def augmentString(x: String): StringOps = new StringOps(x)
隐式方法augmentString
将String转换成了StringOps
,所以:
def main(args: Array[String]): Unit = {val str:String = "20"val i = str.toInt // 底层代码实现:augmentString(str).toIntprintln(i)}
好了,通过以上代码分析,我们知道StringOps
中存在toInt
方法,所以通过隐式转换将str转成StringOps后就可以调用toInt了。
分析Int相关的源码
接下来,我们继续分析Int类的源码:
final abstract class Int private extends AnyVal {//省略代码def toInt: Intdef toLong: Long//省略代码}
通过查看Int的源码发现在Int中也存在一个toInt
的方法,那么现在如果也存在一个将String转成Int的隐式方法,那么,String也能调用toInt
了。分析到这里,我们渐渐的感觉到发现冲突产生的地方了,好的,我们马上来看看我们写的隐式方法的代码:
/*** 定义的隐式方法* 该方法的功能是将String转成Int* @param str 需要转换的字符串* @return 返回 Int*/
implicit def strToInt(str:String):Int= {/*** 通过分析我们知道StringOps和Int都有toInt方法,所以* str.toInt在这里有两个隐式函数都可以进行转换* 1、使用scala.Predef 中的* implicit def augmentString(x: String): StringOps = new StringOps(x)* 所以str.toInt 就等价于 augmentString(str).toInt** 2、使用自己定义这个隐式方法(递归调用)* augmentString 就等价于 strToInt(str).toInt** 好了,我们知道隐式转换只能匹配一个,不能有多个,* 而这里str.toInt找到两个隐式转换都可以实现,所以出现了之前“模棱两可”的错误信息*/str.toInt}
既然分析清楚了出现错误的原因,接下来我们就根据原因来看看如何解决吧。
解决方法的本质就是不要让toInt隐式转换的时候找到多个隐式方法出现“模棱两可”。
解决方案
方案一
使用Integer.parseInt(str)
替换str.toInt
。完整代码代码如下:
object TestDemo {def main(args: Array[String]): Unit = {val str:Int = "20"println(str)}implicit def strToInt(str:String):Int= {Integer.parseInt(str)}}
使用Integer.parseInt(str)
替换str.toInt
,没有使用str.toInt
了,隐式转换自然就就没有了。
方案二
使用new StringOps(str).toInt
替换str.toInt
。完整代码代码如下:
object TestDemo {def main(args: Array[String]): Unit = {val str:Int = "20"println(str)}implicit def strToInt(str:String):Int= {new StringOps(str).toInt}}
使用new StringOps(str).toInt
替换str.toInt
。这里使用new StringOps(str)
显式调用了toInt
,所以也没有隐式转换了。
方案三
将自己定义的隐式方法implicit def strToInt(str:String):Int
的返回值省略,该方法就不能被递归调用了,那这时候str.toInt
就只有implicit def augmentString(x: String): StringOps
这一个隐式转换方法了,也解决了两个隐式方法的冲突问题。完整代码如下:
object TestDemo {def main(args: Array[String]): Unit = {val str:Int = "20" // errorprintln(str)}implicit def strToInt(str:String) = {str.toInt}}
以上代码第四行val str:Int = "20"
编译错误,错误信息如下:
Error:(8, 19) type mismatch;found : String("20")required: IntNote: implicit method strToInt is not applicable here because it comes after the application point and it lacks an explicit result typeval str:Int = "20"
出现该错误的原因是:
隐式方法没有显式给出返回类型,必须位于应用点之前
所以正确代码如下:
object TestDemo {implicit def strToInt(str:String) = {str.toInt}def main(args: Array[String]): Unit = {val str:Int = "20"println(str)}}
好了,到这里我们的问题分析及解决方案就结束了,希望对大家有所帮助。
by 木子李 更多技术文章
Scala隐式转换的问题分析--String隐式转换为Int相关推荐
- sql隐式转换_SQL Server中的隐式转换
sql隐式转换 This article will provide an overview of SQL Server implicit conversion including data type ...
- c# 无法将类型隐式转换_C#中的隐式类型数组
c# 无法将类型隐式转换 C#隐式类型数组 (C# Implicitly Typed Arrays) Like implicitly typed variables, we can also decl ...
- php隐式转换,隐式转换如何使用?总结隐式转换实例用法
JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object.object是引用类型,其它的五种是基本类型或者是原始类型.我们可 ...
- oracle隐式转换能禁用吗,Oracle隐式转换
和其他的关系型数据库一样, oracle 中也能进行一些隐式的数据转换,这对我们写 SQL 语句有 非常 用,我们可以不必麻烦地手动转化很多类型的字符.虽然前面我们介绍了一些使用例如to_char,t ...
- android 尺寸转换 dp sp in mm pt px转换为int
在android开发中,在自定义view中有些函数只接受int参数,而我们经常使用的尺寸单位是dp.sp这些,那如何将它们转换为int型呢? int spToInt=TypedValue.applyD ...
- 2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数
目录 隐式转换和隐式参数 隐式转换 自动导入隐式转换方法 隐式转换的时机 隐式参数 隐式转换和隐式参数 隐式转换和隐式参数是scala非常有特色的功能,也是Java等其他编程语言没有的功能.我们可以很 ...
- scala中的隐式转换、隐式参数和隐式类
scala中的隐式转换.隐式参数和隐式类 @(SCALA)[scala] scala中的隐式转换隐式参数和隐式类 一隐式转换 1示例 2隐式转换的条件 二隐式参数 1示例 三隐式类 1示例 隐式转换是 ...
- Scala入门到精通——第十九节 隐式转换与隐式参数(二)
本节主要内容 隐式参数中的隐式转换 函数中隐式参数使用概要 隐式转换问题梳理 1. 隐式参数中的隐式转换 前一讲中,我们提到函数中如果存在隐式参数,在使用该函数的时候如果不给定对应的参数,则编译器会自 ...
- Scala入门到精通——第十八节 隐式转换与隐式参数(一)
本节主要内容 隐式转换简介 隐式转换函数 隐式转换规则 隐式参数 1. 隐式转换简介 在Scala语言当中,隐式转换是一项强大的程序语言功能,它不仅能够简化程序设计,也能够使程序具有很强的灵活性.要想 ...
- scala学习之旅(十三):隐式转换和隐式参数
文章地址:http://www.haha174.top/admin/article/list 1.引言 scala 提供的隐式转换和隐式参数功能,是非常有特色的功能.是java 等编程语言所没有的功能 ...
最新文章
- [lua]判断nginx收到的是否json
- 第十五届全国大学生智能汽车竞赛华南赛区成绩总结
- DSP专家给你一个选择FPGA的理由(让人看了热血沸腾的一篇科普文章)
- eCos Mbox机制
- android layout 层次感,FrameLayout的层次问题
- Kontakt 6 for Mac(强大的音频采样器软件)
- 大数据Hadoop(五):Hadoop架构
- vue实现调用摄像头扫描二维码功能
- 工业机器人技术试题_工业机器人考试试题库
- cadz轴归零命令_CAD中所有图形实现统一标高(Z轴归零)的方法,统一标高的快捷键命令...
- 2013八大免费杀毒软件排行榜
- WinCC界面中通过插件打开pdf文件
- 中学生心理测试系统软件,学校心理测评软件
- 呼叫中心外呼系统与双呼系统对比
- Android 版本号和分支查看
- DNS中cname记录的作用
- [python]pycharm自动生成函数注释
- 数字正交下变频(多相滤波法)
- 电影数据分析——国产烂片深度揭秘
- Android 更换应用图标无效