Implicit conversion from A to Some(a)

后端 未结 3 1947
眼角桃花
眼角桃花 2021-01-23 00:57

out of curiosity, I was wondering if it was possible to do something like :

def myMethod(
  a: Option[A] = None,
  b: Option[B] = None, 
  ...
  z: Option[Z] = N         


        
相关标签:
3条回答
  • 2021-01-23 01:00

    as Luis Miguel Mejía Suárez suggested in the comments, you could use the cats implicit like this:

    import cats.syntax.option.catsSyntaxOptionId
    //import cats.implicits._ //or you could import everything
    
    object Example1 {
      def foo(i: Option[Int]): Boolean = ???
    
      def myFunction(a: Int, b: Int): Int =
        if (foo(a.some)) 0 else b //a.some is from cats implicit
    }
    

    What you don't want to do is expand your function to take more values just so the type matches some internal implementation.

    object Example2 {
      def foo(i: Option[Int]): Boolean = ???
    
      // don't take an option if you don't expect None
      def myFunction(a: Option[Int], b: Int): Int =
        if (foo(a)) 0 else b
    }
    

    If you're not taking None as a parameter, it's perfectly fine to convert values explicitly when you need to:

    object Example3 {
      def foo(i: Option[Int]): Boolean = ???
    
      def myFunction(a: Int, b: Int): Int =
        if (foo(Some(a))) 0 else b
    }
    
    0 讨论(0)
  • 2021-01-23 01:01

    Possible, yes:

    object Test {
      implicit def anythingToOption[A](a: A): Option[A] = Option(a)
      def foo(something: Option[Int]): Unit = ???
    
      def main(args: Array[String]): Unit = {
        foo(1)
      }
    }
    

    Should you do this? NO. Why? Because implicits with such broad scopes are dangerous. For one, they can lead to ambiguity when you actually need a relevant implicit in scope. Second, when someone reads this, they'll need to see where this conversion happens, and why. Third, this can lead to subtle bugs.

    Instead, you can use extension methods, whether you get them from the Cats library or write them yourself:

    object Test {
      implicit class OptionOps[A](val a: A) extends AnyVal {
        def toOption: Option[A] = Option(a)
        def some: Option[A] = Some(a)
      }
    
      def foo(something: Option[Int]): Unit = ???
      def main(args: Array[String]): Unit = {
        foo(1.toOption)
        foo(1.some)
      }
    }
    
    0 讨论(0)
  • 2021-01-23 01:01

    My favorite solution is this:

    class Opt[A](val value: Option[A]) extends AnyVal
    object Opt {
       implicit def fromA[A](x: A): Opt[A] = new Opt(Some(x))
       implicit def toOption[A](x: Opt[A]): Option[A] = x.value
       def N[A]: Opt[A] = new Opt(None) 
    }
    
    def myMethod(
      a: Opt[A] = Opt.N,
      ...
      z: Opt[Z] = Opt.N
    ): Something = ...
    

    Because Opt is used only for default parameters, the implicit conversions are harmless.

    0 讨论(0)
提交回复
热议问题