'Scala - How to add new methods to existing classes'에 해당되는 글 1건

  1. 2014.03.28 Scala - How to add new methods to existing classes
00.scala2014. 3. 28. 12:57
반응형

Update: This article was written for Scala 2.9. Things changed a little bit in Scala 2.10, so see this new article, Creating implicit methods in Scala 2.10, for correct examples for 2.10 and newer versions of Scala.

A cool thing about implicit conversions in Scala is that they let you add new methods to existing classes, including existing Java and Scala classes such as String, File, and so on.

For instance, let's say you want to add a method to the Java String class, and this new method will increment each character in the String by one byte. The first thing you do is define a Scala class that has a method that implements the behavior you want:

class BetterString(val s: String) {
  def increment = s.map(c => (c + 1).toChar)
}

In that class I created a new method named increment, which uses the String the class is created with, and returns a new String, where each character in the String has been increased by one byte ('A' becomes 'B', 'B' becomes "C', and so on).

Next, I define an implicit conversion that ties my new class to the existing Java String class:

implicit def stringToString(s: String) = new BetterString(s)

Notice that the stringToString method is a very normal looking Scala function, but because it's preceded by the implicit keyword, some very cool "magic" happens. Here's how this works:

  • Because my implicit method stringToString accepts a String as input, Scala is smart enough to know that every time I have a String value, such as a String literal, it should look in my BetterString class for additional methods that accept a String as a parameter. (The implicit keyword has a lot of power.)
  • In my BetterString class I've defined my increment method, and it does the work of walking through each character in a String, incrementing that Char by one byte, and then returning the entire sequence of new characters when it's finished iterating over the String.

As a result, I've tied my increment method to the String class, so I can now type something like this:

"foo".increment

Testing it in the Scala REPL

If you're new to implicit conversions, I'm sure that's still a little hard to understand, so let's take a look at how this works in the Scala REPL. First we define our class:

scala> class BetterString(val s: String) {
     | def increment = s.map(c => (c + 1).toChar)
     | }
defined class BetterString

That looks just like a normal Scala class, no magic there. Next we define our stringToString function:

scala> implicit def stringToString(s: String) = new BetterString(s)
stringToString: (s: String)BetterString

Again, except for the implicit keyword, that looks like a normal function.

And now it's time for the big test. Let's create a String literal and then see if our increment method will work:

scala> "HAL".increment
res0: String = IBM

As you can see from that last line, I typed in the String "HAL", then followed it with my increment method, and that method returned a new String "IBM", which is the result of incrementing each character by one byte.

Posted by 1010