在很多情况下,我使用Option
形式的参数作为默认值None
- 如下所示:
def foo(bar:Option[String] = None)
这很方便,让我可以轻松省略null
。但是,如果我这样做,我需要将方法的每次调用更改为
foo(Some("bar"))
而不是简单
foo("bar")
然而,这看起来有点多余,因为很明显,当我指定一个值时,它是一个完整的选项。我很确定我可以尝试编写一些隐式转换器来为我做这样的包装 - 不幸的是,我不知道如何。
奖金 - 这是理智的做法吗?有没有其他方法来处理" nullable"参数?
答案 0 :(得分:6)
我会给你一些选择(双关语)。
请勿使用可选参数,而是使用Option.apply
。当参数不一定是可选的,但您希望处理可能传递的null
值时,这非常有用。
def foo(bar: String): ?? = Option(bar)... // operate on the Option[String]
这样做的好处是Option.apply
会自动将null
转换为None
,因此绝对不需要使用if / else。
对非可选参数使用重载。当参数真正是可选的时,情况更是如此,但是为您提供了传递Option
包装或解包的便利性。但是,如果不首先知道类型,就不可能在此处传递null
。
def foo(bar: String): ?? = foo(Option(bar))
def foo(bar: Option[String]): ?? = ???
示例:
def foo(bar: String): Option[String] = foo(Option(bar))
def foo(bar: Option[String]): Option[String] = bar.map(_ + "aaa")
scala> foo("bbb")
res7: Option[String] = Some(bbbaaa)
scala> foo(null: String) // The String ascription is necessary here.
res9: Option[String] = None
scala> val str: String = null
scala> foo(str) // No ascription necessary, since we know the type.
res10: Option[String] = None
将任何内容隐式转换为Option
。
implicit def any2Opt[A](value: A): Option[A] = Option(value)
并保持目前的定义
def foo(bar: Option[String]): ?? = ???
隐式转换为Option
会导致一些意想不到的结果,所以要小心。
答案 1 :(得分:1)
您可以将所需的通用隐式写为
implicit def wrapToOption[T](x: T) = Option[T](x)
然后你可以做
def foo(bar: Option[String] = None) = println(bar)
foo("bar") //> Some(bar)
foo() //> None
def fooBar(bar: Option[Int] = None) = println(bar)
fooBar(2) //> Some(2)
关于这是理智的事情,我会说不(个人意见)。众所周知,Implicits很难调试。错误的逻辑错误可能会让你的生活陷入困境。
此外,团队的每一个新成员都必须讲授所有这些"魔法"发生在幕后。
答案 2 :(得分:1)
将参数类型设置为Option[_]
是一种非常合理的方法,如果它们确实是可选的。但是,我不建议使用implicits直接转换为Option[_]
。
通过包含Scalaz并使用some
,您可以使语法更容易:
foo("hello".some)
如果您不想为此引入Scalaz,那么编写自己的隐式代码非常容易。这种隐式更好,因为你明确地调用some
方法来“触发”隐式,而不是“魔法”转换。
另一种选择,如果你经常调用一个参数设置为Some[_]
的函数来重载它(同样,我也不是过载的粉丝):
def foo(x: Option[String] = None, y: Option[Int] = None, z: Option[String] = None) { /* do stuff */ }
def foo(x: String, y: Int, z: Option[String] = None) = foo(x.some, y.some, z)
最后说明,如果函数明确将它们定义为可选,我认为在Some
中包装参数没有任何问题。我不会太担心这种语法。
答案 3 :(得分:0)
您可以将隐式转换器定义为:
implicit def conv(str: String): Option[String] = {
if (str == null) None else Some(str)
}
def foo(bar: Option[String] = None) = {
bar
}
输出:
scala> foo("xyz")
res55: Option[String] = Some(xyz)
scala> foo()
res1: Option[String] = None
答案 4 :(得分:0)
将所有内容隐式转换为Option
是一种危险的游戏,我会避免!您可能更喜欢简单地使用一些方法重载:
object Foos {
private def foo(bar: Option[String]): Unit = println(bar.getOrElse("foobar"))
def foo(bar: String): Unit = foo(Some(bar))
def foo(): Unit = foo(None)
}
然后你可以这样做:
Foos.foo("barfoo") //prints "barfoo"
Foos.foo() //prints "foobar"
虽然仍然只是真正实施一次方法。此外,您可以通过这种方式隐藏Option
重载。