How to wrap a method having implicits with another method in Scala?

前端 未结 1 1449
遇见更好的自我
遇见更好的自我 2020-12-21 04:27

I have a method with implicits:

def f(x: String)(implicit dispatcher: ExecutionContextExecutor, mat: ActorMateriali         


        
相关标签:
1条回答
  • 2020-12-21 04:57

    Idiomatic solution is to repeat implicit parameters.

    If you repeat the same set of implicit parameters many times then idiomatic solution is to introduce your type class (or just single implicit) instead of that set of implicits and use this type class.

    Not idiomatic solution is to introduce macro annotation that will generate implicit parameter section for methods.

    Sometimes you can transfer implicits to some level above

    class MyClass(implicit val ec: ExecutionContext) extends ExecutionContextAware {
      def f(x: String) = ???
      def g(y: String) = f("xxx" + y)
    }
    
    trait ExecutionContextAware {
      implicit def ec: ExecutionContext
    }
    

    or

    trait MyTrait extends ExecutionContextAware {
      def f(x: String) = ???
      def g(y: String) = f("xxx" + y)
    }
      
    object Impl extends ExecutionContextAware {
      implicit def ec: ExecutionContext = ExecutionContext.Implicits.global
    }
    
    trait ExecutionContextAware {
      implicit def ec: ExecutionContext
    }
    

    Could you please also give an example with typeclass?

    Suppose you have multiple type classes

    trait TC1[A] {
      def foo = ???
    }
    trait TC2[A] {
      def bar = ???
    }
    

    and you have to repeat them in methods

    def f[A](implicit tc1: TC1[A], tc2: TC2[A]) = ???
    

    1. Then you can introduce your type class

    trait TC[A] {
      def foo
      def bar
    }
    

    express it via TC1, TC2, ...

    object TC {
      implicit def mkTC[A](implicit tc1: TC1[A], tc2: TC2[A]): TC[A] = new TC[A] {
        def foo = tc1.foo
        def bar = tc2.bar
      }
    }
    

    and use it

    def f[A](implicit tc: TC[A]) = ???
    

    2. Alternative approach is

    trait TC[A] {
      implicit def tc1: TC1[A]
      implicit def tc2: TC2[A]
    }
    
    object TC {
      implicit def mkTC[A](implicit _tc1: TC1[A], _tc2: TC2[A]): TC[A] = new TC[A] {
        implicit def tc1: TC1[A] = _tc1
        implicit def tc2: TC2[A] = _tc2
      }
    }
    
    def f[A](implicit tc: TC[A]) = {
      import tc._
      ???
    }
    

    In your example with ExecutionContextExecutor, ActorMaterializer (for example following the 2nd approach) you can introduce

    trait MyImplicit {
      implicit def dispatcher: ExecutionContextExecutor
      implicit def mat: ActorMaterializer
    }
    

    and replace

    def f(x: String)(implicit dispatcher: ExecutionContextExecutor, mat: ActorMaterializer) = ???
    

    with

    def f(x: String)(implicit mi: MyImplicit) = {
      import mi._
      ???
    }
    
    0 讨论(0)
提交回复
热议问题