Scala中带有选项值或默认参数的方法调用

ABi*_*ika 5 default scala higher-order-functions scala-option

我是Scala的新手,偶然发现了一个小问题,这个问题一直困扰着我。假设有一些带有默认参数的方法

def foo(v: Any = "default"): String = s"called with parameter '$v'"
Run Code Online (Sandbox Code Playgroud)

和一个Option val opt: Option[String]。如何使用选项值(如果已定义)或默认参数调用此方法?我的意思是尽管有明显的解决方案

val result = if (opt.isDefined)
               from.here.to.foo(opt.get)
             else
               from.here.to.foo()
Run Code Online (Sandbox Code Playgroud)

并且不得不用对象链(可能很长)键入两次该方法?更不用说具有多个可选/默认参数了...


我所能想到的就是无助的帮手

def definedOrDefault[A, B](opt: Option[A], f0: => B, f1: A => B): B =
  if (opt.isDefined) f1(opt.get) else f0
Run Code Online (Sandbox Code Playgroud)

但是当无法在高阶函数中提及默认参数时,就是这样。让我想起了Java过去的糟糕时光,其中方法重载会产生相同的问题。

Łuk*_*asz 6

It seems like you are using two concepts of value being optional in one place, i.e. optional parameter and Option. They don't like play well together, maybe it is better to use just one.

If you always just pass value of Option to a method or pass nothing to get default value, maybe consider changing the function to accept the Option.

def foo(v: Option[String]) = {
  val param = v getOrElse "default"
  s"called with parameter '$param'"
}
Run Code Online (Sandbox Code Playgroud)

If you still want to have default parameter you can change signature to

def foo(v: Option[String] = None)
Run Code Online (Sandbox Code Playgroud)

This approach however will require you to wrap your parameter into Some when you do a regular call e.g.

foo(Some("regular param"))
Run Code Online (Sandbox Code Playgroud)

but it works well when you use Options. You can easly add more optional parameters as well.

Here is an example

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
Run Code Online (Sandbox Code Playgroud)

You could also introduce implicit conversion from Any to Option, that would let you to omit Some, but I don't think it is such a good idea

 implicit def any2option[A](e: A): Option[A] = Some(e)
Run Code Online (Sandbox Code Playgroud)