Implicit
Magic?!
1. Assign parameter with a wrong type?!
var a: String = "Hello"
a = "See you"
a = 1 //???
2. Invoke a missing function?!
class A {def log(): Unit = "logs...balabala"}
val a = new A()
a.log()
a.show() //???
3. Invoke function without enough parameters?!
def f(a: Int)(b: Int): Int
val a = f(1)(2)
val b = f(1) //???
Overview
What is Implicit in Scala?
Definition
When to use Implicit?
Importing Implicits
Rules for Implicit Conversions
-
Extension
- How to give the default value of parameters?
- How to restrict the type parameter?
What is Implicit in Scala?
Implicits are a powerful, code-condensing feature of Scala
It is usually used in type conversion and function/class parameter and happens in compilation phase.
Definition
1. Variable
implicit val a:Int = 1
2. Method
implicit def int2Str(v:Int):String = v.toString
3. Class
implicit class Show(a: A) {
def show(): Unit = println("This is an implicit show method.")
}
4. Method Parameter
def sort[A](l:List[A])(implicit order:Ordering[A])
5. Class Parameter
class Ages(ages:List[Int])(implicit order:Ordering[Int])
6. Type Parameter
def sort[A:Ordering](l:List[A])
When to use Implicit?
1. Type mismatch
If the type of an expression differs from the expected type
var a: String = "Hello"
a = 1
implicit def int2str(v: Int): String = v.toString
2. Access nonexistent member
If an object accesses a nonexistent member
class A {def log(): Unit = "logs...balabala"}
val a = new A()
a.show()
implicit class Show(a: A) {
def show(): Unit = println("This is implicit show method.")
}
3. Missing parameters
If an object invokes a method whose parameters don't match the give arguments
def f(a: Int)(implicit b: Int): Int
val a = f(1)(2)
val b = f(1)
implicit val b: Int = 0
Importing Implicits
1. Implicit functions or classes in the companion object of the source or target type
object AccessNonexistentMember {
def main(args: Array[String]): Unit = {
val a = new A()
a.show()
}
}
class A { def log(): Unit = ???}
object A {
implicit class Show(a: A) {
def show(): Unit = println("This is implicit show method.")
}
}
2. Implicit functions or classes that are in scope
object TypeMismatch {
def main(args: Array[String]): Unit = {
import IntConversion.int2str
var a: String = "Hello"
a = 1
}
}
object IntConversion {
implicit def int2str(v: Int): String = v.toString
}
Rules for Implicit Conversions
1. Only trigger by error
No implicit conversion is used if the code compiles without it
- Type mismatch
- Access nonexistent member
- Missing parameters
2. Only one match
Ambiguous conversions are an error. For example, if both convert1(a) * b
and convert2(a) * b
are valid, the compiler will report an error.
3. Only do once
The compiler will never attempt multiple conversions, such as convert1(convert2(a)) * b
case class Name(v: String)
object Name {
implicit def str2Name(v: String): Name = Name(v)
}
object Test {
implicit def int2Str(v: Int): String = v.toString
}
val me: Name = "Yaxin"
val age: String = 18
val num: Name = 89757 //error: type mismatch(Compilation Failed)
Extension
- How to give the default value of parameters?
- How to restrict the type parameter?
How to give the default value of parameters?
def sort[A](l: List[A])(implicit order: Ordering[A]) = l.sorted
sort(List(3, 1, 2))
sort(List(3, 1, 2))(implicitly[Ordering[Int]].reverse)
def f(a: Int)(implicit b: Int): Unit = println(s"f: a is $a, b is $b")
def g(a: Int)(b: Int = 0): Unit = println(s"g: a is $a, b is $b")
How to restrict the type parameter?
def compare[A: Ordering](x: A, y: A): Int = implicitly[Ordering[A]].compare(x, y)
compare(1, 2)
compare(Age(1), Age(3)) //No implicit Ordering defined for Age (Compilation Failed)