我对Scala很陌生,偶然发现了一个一直困扰着我的小问题。让我们说有一些默认参数的方法
def foo(v: Any = "default"): String = s"called with parameter '$v'"
和选项val opt: Option[String]
。
如何使用选项值(如果已定义)或默认参数调用此方法?
我的意思是尽管有明显的解决方案
val result = if (opt.isDefined)
from.here.to.foo(opt.get)
else
from.here.to.foo()
并且必须两次输入(可能很长)对象链的方法?更不用说有多个可选/默认参数......
我所能想到的只是无助的帮助者
def definedOrDefault[A, B](opt: Option[A], f0: => B, f1: A => B): B =
if (opt.isDefined) f1(opt.get) else f0
但是当不能在高阶函数中提及默认参数时......就是这样。让我想起Java过去的糟糕时期,方法重载会产生同样的问题。
答案 0 :(得分:3)
您似乎在一个地方使用两个值为可选的概念,即可选参数和Option
。他们不喜欢一起玩,也许最好只使用一个。
如果您始终只将Option
的值传递给方法或传递任何内容以获取默认值,则可以考虑更改函数以接受Option
。
def foo(v: Option[String]) = {
val param = v getOrElse "default"
s"called with parameter '$param'"
}
如果您仍想拥有默认参数,可以将签名更改为
def foo(v: Option[String] = None)
然而,这种方法要求您在进行常规通话时将参数包装到Some
,例如
foo(Some("regular param"))
但使用Option
时效果很好。您也可以轻松添加更多可选参数。
这是一个例子
def foo(v1: Option[String] = None, v2: Option[Int] = None) = {
val param1 = v1 getOrElse "default"
val param2 = v2 getOrElse 42
s"'$param1', '$param2'"
}
foo() // "default", 42
foo(v2 = Some(12)) // "default", 12
foo(Some("asd"), Some(11)) // "asd", 11
val optionFromSomewhere = Some("a")
val anotherOptionFromSomewhere = Option.empty[Int]
foo(optionFromSomewhere, anotherOptionFromSomewhere) // "a", 42
您还可以引入从Any
到Option
的隐式转换,这样可以省略Some
,但我认为这不是一个好主意
implicit def any2option[A](e: A): Option[A] = Some(e)
答案 1 :(得分:2)
对@Łukasz的回答略有延伸,这个回答太大而无法发表评论:
通过创建专用类型,您可以避免在没有危险Some
的{{1}}中包装当前参数:
any2option
使这更安全的原因是sealed trait OptParam[+A] { def toOption: Option[A] }
case class Param[+A](value: A) extends OptParam[A] { def toOption = Some(value) }
case object NoParam extends OptParam[Nothing] { def toOption = None }
object OptParam {
implicit def any2optParam[A](x: A): OptParam[A] = Param(x)
}
def foo(v1: OptParam[String] = NoParam, v2: OptString[Int] = NoParam) = {
val param1 = v1.toOption.getOrElse("default")
val param2 = v2.toOption.getOrElse(42)
s"'$param1', '$param2'"
}
foo("a") // "'a', '42'"
应该只作为方法参数类型出现,因此转换不会在您不期望的地方触发。
答案 2 :(得分:0)
您可以使用map
上定义的Option
函数来转换包含在其中的值(如果已定义)。这看起来像这样:
opt.map(foo)
// same as
opt.map(x => foo(x))
如果某个值在内部,则返回Option[String]
,如果之前为None
则返回None
。
以下是REPL的完整示例:
scala> def foo(v: Any = "default"): String = s"called with parameter '$v'"
foo: (v: Any)String
scala> Some("Hello")
res0: Some[String] = Some(Hello)
scala> res0.map(foo)
res1: Option[String] = Some(called with parameter 'Hello')
scala> val x: Option[String] = None
x: Option[String] = None
scala> x.map(foo)
res2: Option[String] = None
修改强>
要使用默认值调用它,您应该在调用之前匹配您的选项,因为该方法需要非Option
参数。
val optOrDefault = opt getOrElse "default"
foo(optOrDefault)