Scala3 Implicit

Posted 楠爸自习室

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala3 Implicit相关的知识,希望对你有一定的参考价值。

Scala3 did lots of improvement in Implicit, which is the most painful feature in Scala2.

A quick summary is

  • Improve the error log to help the developer find the correct implicit instance.
  • Split the implicit feature into given/using and extension to make the feature more clear.

Now let's have a taste of these features.

How to pass parameters implicitly?

Scala2

def add(x: Int)(implicit y: Int): Int = x + y

implicit val instance: Int = 10 // :Int = 10

add(1// :Int = 11
add(1)(5// :Int = 6

Scala3

def add(x: Int)(using y: Int): Int = x + y

given instance: Int = 10

add(1// :Int = 11
add(1)(using 5// :Int = 6

Difference

  • Replace implicit with using in function parameter
  • Replace implicit val with given in instance definition
  • Use using explicitly when giving explicit value

With these changes, the code readability is improved. At least we can search given to find the implicit instances and search using to find the implicit parameters.

How to use context bound?

Scala2

trait Show[A{
 def show(x: A): String
}

def printListWithUsing[A](list: List[A"A")(implicit show: Show[A]): String = list.map(x => show.show(x)).mkString(";")
def printListWithContextBound[A:Show](list: List[A"A:Show"): String = list.map(x => implicitly[Show[A]].show(x)).mkString(";")

implicit val intShow: Show[Int] = new Show[Int] {
  def show(x: Int): String = x.toString 
}

printListWithUsing(List(1234)) // :String = "1;2;3;4"
printListWithContextBound(List(1234)) // :String = "1;2;3;4"

Scala3

trait Show[A{
 def show(x: A): String
}

def printListWithUsing[A](list: List[A"A")(using show: Show[A]): String = list.map(x => show.show(x)).mkString(";")
def printListWithContextBound[A:Show](list: List[A"A:Show"): String = list.map(x => summon[Show[A]].show(x)).mkString(";")

given intShow: Show[Intwith {
  def show(x: Int): String = x.toString 
}

printListWithUsing(List(1234)) // :String = "1;2;3;4"
printListWithContextBound(List(1234)) // :String = "1;2;3;4"

Difference

  • Replace implicitly with summon

  • Replace new class with with

    Not like Scala2, we don't need to new the implicit class explicitly, all the members of class will be wrapped by with keyword.

    implicit val intShow: Show[Int] = new Show[Int] { ... } // Scala2
    given intShow: Show[Intwith { ... } // Scala3

How to add function to an existing class?

Scala2

trait Show[A{
 def show(x: A): String
}

implicit class ShowOps[AShow](v: A "AShow"{
  def show(): String = implicitly[Show[A]].show(v)
}

implicit val intShow: Show[Int] = new Show[Int] {
  def show(x: Int): String = x.toString 
}

implicit def listShow[AShow]: Show[List[A]] = new Show[List[A]] {
  def show(v: List[A]): String = v.map(_.show()).mkString(";"
}

1.show() // :String = "1"
List(123).show() // :String = "1;2;3"

Scala3

trait Show[A{
 extension (v: A) {
   def show(): String
 }
}

given intShow: Show[Intwith {
  extension (v: Int) {
    def show(): String = v.toString()
  }
}

given listShow[AShow]: Show[List[A]] with {
  extension (v: List[A]) {
    def show(): String = v.map(_.show()).mkString(";")
  }
}

1.show() // :String = 1
List(123).show() // :String = "1;2;3"

Difference

In Scala2, we usually define a type class first, then use an implicit class to add the function to the existing type.

In Scala3, it becomes straightforward, use a new keyword extension to do that.

The magic thing is all the methods in extension will be translated to functions, the following two expressions are equal

extension(v: Int) {
  def demo():String = v.toString
}

// equals to def demo(v: Int)() = v.toString

1.demo() // :String = 1
demo(1)() // :String = 1

Summary

According to my experience, Scala3 implicit is easier than Scala2, but there are still complicated rules for implicit finding, will talk about them later.

You can find the demo code here

  • Scala2 [1]
  • Scala3 [2]

参考资料

[1]

Scala2: https://gist.github.com/sjmyuan/b17cccaecea669d88e65b9c89f3efeb5

[2]

Scala3: https://gist.github.com/sjmyuan/e588de4ec27b735d8cda97050237fd8d


关注【楠爸自习室】



以上是关于Scala3 Implicit的主要内容,如果未能解决你的问题,请参考以下文章

初学scala3——使用future实现并发

错误代码:1267。操作“=”的排序规则(utf8_general_ci,IMPLICIT)和(utf8_unicode_ci,IMPLICIT)的非法混合

Scala3:越过终点线

Scala3元编程-内联

离子错误 v.context.$implicit 未定义

如何从 Enum Scala3 中随机选择元素