在 Scala 中使用选项值或默认参数调用方法
Method call with option value or default parameter in Scala
我是 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()
并且必须使用(可能很长的)对象链键入方法两次?更不用说有一个以上的 optional/default 参数...
我能想到的就是无用的帮手
def definedOrDefault[A, B](opt: Option[A], f0: => B, f1: A => B): B =
if (opt.isDefined) f1(opt.get) else f0
但是当不能在高阶函数中提及默认参数时……就是这样。让我想起了 Java 过去的糟糕日子,方法重载会产生同样的问题。
您似乎在一个地方使用了两个值可选的概念,即可选参数和 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
s 时效果很好。您也可以轻松添加更多可选参数。
这是一个例子
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)
您可以使用 Option
上定义的 map
函数来转换包含在其中的值(如果已定义)。这看起来像这样:
opt.map(foo)
// same as
opt.map(x => foo(x))
这将 return 一个 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)
对 @Łukasz 的回答进行了轻微扩展,但由于太大而无法放入评论中:
您可以通过创建特殊用途的类型来避免必须将现有参数包装在 Some
中而没有危险 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'"
更安全的是 OptParam
只应作为方法参数类型出现,因此不会在您不期望的地方触发转换。
我是 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()
并且必须使用(可能很长的)对象链键入方法两次?更不用说有一个以上的 optional/default 参数...
我能想到的就是无用的帮手
def definedOrDefault[A, B](opt: Option[A], f0: => B, f1: A => B): B =
if (opt.isDefined) f1(opt.get) else f0
但是当不能在高阶函数中提及默认参数时……就是这样。让我想起了 Java 过去的糟糕日子,方法重载会产生同样的问题。
您似乎在一个地方使用了两个值可选的概念,即可选参数和 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
s 时效果很好。您也可以轻松添加更多可选参数。
这是一个例子
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)
您可以使用 Option
上定义的 map
函数来转换包含在其中的值(如果已定义)。这看起来像这样:
opt.map(foo)
// same as
opt.map(x => foo(x))
这将 return 一个 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)
对 @Łukasz 的回答进行了轻微扩展,但由于太大而无法放入评论中:
您可以通过创建特殊用途的类型来避免必须将现有参数包装在 Some
中而没有危险 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'"
更安全的是 OptParam
只应作为方法参数类型出现,因此不会在您不期望的地方触发转换。