Why conversion is explicit
Scala keeps types apart. A String is never used as an Int behind your back, and a Double is never silently cut down to an Int. When you really want a value in another type, you ask for it with a conversion method:
val score = 42
val scoreStr = score.toString // "42"
val weight = 70.8
val weightInt = weight.toInt // 70
val count = "100"
val countInt = count.toInt // 100
The common conversions are:
| Call | From | To |
|---|---|---|
x.toString | number or other value | String |
s.toInt | String | Int |
s.toDouble | String | Double |
d.toInt | Double | Int |
n.toDouble | Int | Double |
The compiler enforces this. val x: Int = 9.99 is rejected with Found: Double and Required: Int. You must write 9.99.toInt if cutting the decimal part is what you want.
Converting numbers to numbers
toInt on a Double drops the fractional part and does not round. It moves toward zero:
println(9.99.toInt) // 9
println(-9.99.toInt) // -9
println(math.round(9.99)) // 10
Use math.round when you want the nearest whole number. A value too big for an Int doesn't wrap around. It is clamped to the largest Int: 3.0e10.toInt is 2147483647.
Going the other way is safe. An Int becomes a Double with toDouble, and Scala also does it automatically where a Double is required, as in val d: Double = 5. This matters for division. 7 / 2 is 3 because both sides are Int, but 7.toDouble / 2 is 3.5.
Converting strings to numbers
Turning text into a number is parsing, and it can fail. If the text isn't a valid number, the call throws a NumberFormatException while the program runs:
println("2024".toInt + 1) // 2025
println("3.5".toDouble) // 3.5
println("3.5".toInt) // throws: For input string: "3.5"
println("abc".toInt) // throws: For input string: "abc"
Note that "3.5".toInt fails: a string with a decimal point is not an integer. Convert it with toDouble first, and then call toInt if needed.
When the text comes from outside your control, use toIntOption. It returns an Option instead of throwing:
println("12".toIntOption) // Some(12)
println("abc".toIntOption) // None
Converting to a string
toString works on any value. Both 25.toString and 25.toString() compile and give "25". The version without parentheses is the usual style in Scala. The result is a string, so 25.toString + "!" is "25!", and its length is 2.
The exercise step by step
The starting code has an integer, a decimal and a string:
val age = 25
val price = 9.99
val year = "2024"
- Number to text. Declare
ageStrand assign it the string form ofagewithtoString. - Decimal to whole number. Declare
priceIntand assign itprice.toInt. The result is9, not10, because the decimal part is dropped. - Text to number. Declare
yearIntand assign ityear.toInt. The string"2024"is a valid whole number, so this gives2024.
The solution in Scala
val age = 25
val price = 9.99
val year = "2024"
val ageStr = age.toString()
val priceInt = price.toInt
val yearInt = year.toInt
The values are "25", 9 and 2024. The indentation is only whitespace. Scala doesn't care about it in a plain sequence of statements. The call age.toString() has parentheses and price.toInt doesn't. Both forms work here, and the choice is a matter of style.
Common mistakes
- Expecting rounding.
9.99.toIntis 9. Usemath.roundfor rounding. - Parsing text that isn't a clean number. A letter, a decimal point, or an empty string makes
toIntthrow. Whitespace also counts, so calltrimfirst if the text may have spaces around it. - Assuming the original changes.
age.toStringreturns a new value.ageis still anInt. - Converting too late.
"5" + "5"is"55". Convert to numbers before you add:"5".toInt + "5".toIntis10.
Key takeaways
- Scala never converts between strings and numbers on its own. Call
toString,toIntortoDouble. Double.toInttruncates toward zero, and it never rounds.String.toIntthrowsNumberFormatExceptionon bad input.toIntOptionreturnsNoneinstead.
