Scala Implicit detailed

Source: Internet
Author: User

Implicit is a very important feature in Scala and has been thinking about it as much as Java before starting to learn Scala, but it's not as easy to see some of Scala's source code as it is, so I'm going to write a few articles to explain the features of Scala that are different from Java. Implicit, let's get started.

In my opinion, what implicit do is also the main thing Scala do, that is code compression, reduce module code, talk is cheap, first with an example to understand the role of implicit. a chestnut

It'll be Valentine's Day, how will you express your love?

Let's do some preparatory work, first of all to have a lover's interface, including a function to express love Sendlove

Trait Lover {
  def sendlove (love:love) {}
}

And then another love interface, love can not always open in the heart, but should be action, so there is an action function takeaction,event is the event that triggers love, this is of course Valentine's Day this big thing

Trait Love {
  val event:event

  val show = TakeAction (event)

  def takeaction (event:event)
}

Valentine's Day this year is very embarrassing, just in the day before the Chinese New year, so many lovers may be each of the different families to find their mother, so here should be a long distance love, roar roar let you abuse the dog

Class Remotelover extends Lover {}

val lover:lover = new Remotelover

OK, ready to work, Valentine's Day, long-distance lovers to express a wave of love.

Without implicit
lover.sendlove (
  new Love {
    Val event = event ("Valentine is coming!")

    def takeaction (event:event) = {
      println ("Buy a gift!")
    }
)

There is a variety of ways to love you, but the heart that loves you is always the same. may be to send a gift to talk about the heart, may also be flying to your side to give a hug. I'm not pretending to be a saint, I just want to show that in the code above, the only thing that's going to change is this line of code.

println ("Buy a gift!")

Love and its implementation of the function takeaction can be said to be a fixed modular code, if it can be reduced to the following look, it would be great.

Lover.sendlove (
  (_: Event) = println ("Give a hug!")
)

Take a look at what happened. The parameters required for the function sendlove are the Love object:

New Love {
  Val event = event ("Valentine is coming!")

  def takeaction (event:event) = {
    println ("Buy a gift!")
  }
}

But after the reduction, the corresponding parameter becomes a function:

(_: Event) = println ("Give a hug!")

Oh, no. This does not match the parameter type. It's time to think of type conversions. Here is a super-simple example:

"ABC" + 123

Here 123 is Int converted to String, refer to this idea and try to convert the function into love:

Implicit def function2love (f:event = Unit) = new Love {
  Val event = event ("Valentine is coming!")

  def takeaction (event:event): Unit = f (event)
}

At this point the original code can be written as:

Lover.sendlove (
  Function2love (
    (_: Event) = println ("Give a hug!")
  )

Here we explicitly specify the function Function2love for the type conversion, note that the above function2love used the implicit keyword, the role of this keyword can be implicitly convert one type to another type, and do not need to explicitly call, as follows:

With implicit
import lover.function2love

Lover.sendlove (
  (_: Event) = println ("Give a hug!")
)

What's going on here specifically. The first parameter type required for Sendlove is love, but the argument here is a function. When the compiler found that there is a mismatch in the code of the type, it will not immediately error, but choose to salvage first, the way to salvage is to find in the current Code field there is no implicit decorated code, and then found the Function2love this implicit conversion function, code compiled through.

The above is an introductory example of implicit, all code see GITHUB

Generally speaking, the implicit is mainly used in two aspects: implicit conversion and implicit parameters, respectively, the implicit conversion implicit conversion to a desired type

Whenever the compiler discovers type X but requires type Y, it looks for an implicit function that converts x to Y.

For example, under normal circumstances a Double type cannot be converted to an Int type, but we can define an implicit function to implement:

Scala> Implicit def doubletoint (x:double) = X.toint
doubletoint: (x:double) Int

While I'm here to cite an example, the way it goes from Double to Int is not recommended because it loses precision. Conversely, it is normal to go from Int to Double, and the underlying implementation is the implicit conversion. Scala has a Scala. The Predef object, which is introduced into each program by default, contains an implicit conversion like this from a "small" number type to a "large" number type:

Implicit def int2double (x:int): Double = x.todouble

scala> val x:double = 3
x:double = 3.0
implicitly-Class

Implicit classes are new to Scala2.10, in order to make it easier to write wrapper classes. There are several key points: an implicit class cannot be a case class, and the constructor must have only one argument an implicit class must be inside other object,class,trait for an implicit class, the compiler automatically generates an implicit conversion function that produces an implicit class object

For example, a rectangular class Rectangle

Case Class Rectangle (Width:int, Height:int)

Creating a new rectangle requires this:

scala> val rec = Rectangle (3, 4)
rec:rectangle = Rectangle (3,4)

This is still a bit of a hassle, if we want to create a new object by 3 x 4 This way, what to do, this time will use the implicit class:

Implicit class Rectanglemaker (Width:int) {
  def x (height:int) = Rectangle (width, height)
}

Let's create a rectangle again:

scala> val Easyrec = 3 x 4
easyrec:rectangle = Rectangle (3,4)

It seems to be a lot simpler and more straightforward, so how does it come true? As we said earlier, for implicit classes, the compiler automatically generates an implicit conversion function, as follows:

Automatically generated
implicit def rectanglemaker (width:int) = new Rectanglemaker (width)

So when the compiler sees 3 x 4, we first find that the INT 3 has no X function, then we find the implicit conversion, generate a Rectanglemaker (3) by the implicit conversion function above, and then call Rectanglemaker's X function, which produces a rectangle recta Ngle (3,4) implicit parameter

The following is the beginning of the Shing parameter, which is also our most commonly used, the implicit parameter is not used for type conversion, more to reduce the amount of code, the main points are as follows:

An implicit parameter is a list of arguments for a class or function, such as the parameter list where implicit is located

Implicit class Greet (name:string) (implicit Hello:hello, World:world)

Implicit is placed at the top of the parameter list, and they are all implicitly, regardless of the number of arguments.

After defining the implicit parameter, we can omit the argument list when we create a new class or call a function.

Val greet = new greet ("Jack")

Omitting the argument list does not require a parameter list, we need to define all the variables in the implicit argument list using the implicit keyword, and then import the

Implicit val hello = new Hello
implicit val world = new Wrold

Above is some basic points, the year of the dog is coming soon, let us take this as an example to write a home Demo it

Case Class Remote (address:string) Case
class Home (address:string)

Object Transportation {
  def transport ( name:string) (implicit remote:remote, home:home) = {
    println (S "To celebrate Spring Festival, go from $remote to $hom E, by $name ")
  }
}

object Address {
  implicit val remote = new Remote (" Shanghai ")
  implicit val home = NE W Home ("Shanxi")
}

This defines the starting address of remote Home, although it is essentially a String type, but it is best to define a specialized class for implicit arguments, because if you use String as an implicit variable, the compiler may be less likely to find it, or be confused with other implicit variables. , and dedicated classes don't have to worry about that.
There is also a function transport that represents the traffic mode, which uses implicit parameters, and the last Address object defines the implicit variables we need.

And then, ready to go home.

Object GoHome extends App {
  import address._
  transportation.transport ("Airplane")
}

The results are as follows:

To celebrate Spring Festival, go from Remote (Shanghai) to Home (Shanxi), by airplane.
Context Binding

Once we understand the implicit parameters, we can look at another interesting syntactic sugar: context-bound contextual bound

Here I use an example from "Programming in Scala" to ask for the maximum value of all the elements in a list, first we look at the general implementation of the implicit parameter notation:

With implicit
def Maxlistordering[t] (elements:list[t])
                      (implicit ordering:ordering[t]): T =
  elements Match {case
    List () =
      throw new IllegalArgumentException ("Empty lists!")
    Case List (x) + = x Case
    x:: Rest =
      val maxrest = maxlistordering (rest)
      if (ordering.gt (x, maxrest)) x
  else Maxrest
  }

This function has two parameters, one is the List of T, the other is the implicit parameter ordering, and for some common t types, such as Int or String, they all have a default ordering implementation, so you do not need to define their implicit variables to implement the ordering:

println (Maxlistordering (List (1, 5, 10, 3)))

There is a line in the above code that uses the ordering parameter:

if (ordering.gt (x, maxrest)) x

Here ordering is an object of ordering[t], in fact the Scala standard library provides a way for the compiler to find its own implicit variable for a class:

def Implicitly[t] (implicit t:t) = T

For example, a type Foo, call Implicitly[foo] will produce what results. First the compiler looks for the implicit object of Foo, finds the implicitly method that calls the object later, and then returns the object, so the implicit object of Foo can be returned by Implicitly[foo], corresponding to the example above, ordering is ordering [T] An implicit object, in fact we can also use implicitly[ordering[t]] to represent

if (implicitly[ordering[t]].gt (x, maxrest)) x

So now it seems that ordering can use Implicitly[ordering[t]] to replace, then you can omit this parameter name, so-called context binding is to do this thing, grammar is [t:ordering], it mainly do two things: first, A parameter type T is introduced, and secondly, an implicit parameter ordering[t] is added.
A very similar syntax is [t <: Ordering[t]], which means T is a ordering[t].
Now let's take a look at the sort code after the context binding is introduced:

Context bound
def Maxlistordering[t:ordering] (elements:list[t])
                       (implicit ordering:ordering[t]): T =
  Elements match {case
    List () =
      throw new IllegalArgumentException ("Empty lists!")
    Case List (x) + = x Case
    x:: Rest =
      val maxrest = maxlistordering (rest)
      if (implicitly[ordering[t]].gt ( x, Maxrest)) x
      else Maxrest
  }
Summary

Implicit is also very flexible to use, you can mark the implicit keyword in the definition of a variable, function, class, or object. And remember that you want to use implicit, be sure to use import to introduce implicit code (of course, the same Code field example is not required under an object). However, it is also important to note that if you use implicit too frequently, code readability is very low, so before using implicit conversions, take a look at whether you can implement it in other ways, such as inheritance, overloading, if it doesn't work and the code is still redundant, then try implicit to fix it.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.