简体   繁体   中英

more than one implicit conversion in scala

I want to have 2 implicit comvertors in scala

  1. To convert string to int
  2. To convert int to float

     implicit def String2Int(v: String): Int = Integer.parseInt(v) 

The above works but when I write below

 implicit def String2Float(v: String): Float = v.toFloat

It gives compile error cannot resolve symbol to Float

Can we not have 2 implicit converters in one file?

In scala, String does not have toInt, toFloat , etc methods. Where are they taken from?

Scala has Predef object which is imported implicitly in every source (even if you are not importing it).

Predef has the following method:

@inline implicit def augmentString(x: String): StringOps = new StringOps(x)

So it implicitly converts any value of type String to StringOps .

StringOps defines methods:

def toInt: Int         = java.lang.Integer.parseInt(toString)
def toFloat: Float     = java.lang.Float.parseFloat(toString)
...

So when you write str.toFloat - the compiler actually converts String to StringOps and calls the appropriate method.

Ok. What is the problem with your code?

implicit def String2Float(v: String): Float = v.toFloat

Compiler tries to find something that has .toFloat , it finds it in StringOps and in Float via String2Float method. ( Float also has toFloat method).

Compiler "didn't add" the method toFloat (of Predef ) to String because it cannot decide which implicit conversion to apply and implicit conversion from String to StringOps is broken.

So String does not have toFoat method anymore and that's why you have error ( cannot resolve symbol to Float )

(Actually, you should have 2 errors: Note that implicit conversions are not applicable because they are ambiguous: ... AND value toFloat is not a member of String )

Solution is to use

implicit def String2Float(v: String): Float = java.lang.Float.parseFloat(v)

Like you did in Int case.

Now it converts String to Float directly, without implicit conversions (like it was in v.toFloat case)

PS Thank @Dima for pointing to mistake in my answer.

You can define String2Float as:

implicit def String2Float(v: String): Float = {
  val i:Int = v
  i.toFloat
}

or pass implicit converter as:

implicit def String2Float(v: String)(implicit f: String => Int): Float = {
  v.toFloat
}

or get the converter instance implicitly:

implicit def String2Float(v: String): Float = {
  val f = implicitly[String => Int]
  f(v).toFloat
}

In this case compiler resolves everything successfully

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM