Implicit conversion from A to Some(a)

烂漫一生 提交于 2020-01-15 07:20:20

问题


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] = None
): Something = {
  ...
}

What I want is not to have to call it that way:

myMethod(
  b = Some(newB),
  m = Some(newM)
)

but instead being able to just do myMethod(b = newB, m = newM) without having to always convert A to Some(a).

Is it possible ?


回答1:


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)
  }
}



回答2:


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.




回答3:


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
}


来源:https://stackoverflow.com/questions/53974985/implicit-conversion-from-a-to-somea

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!