8

私は Scala にかなり慣れていないので、気になる小さな小さな問題に遭遇しました。デフォルトのパラメーターを持つメソッドがあるとしましょう

def foo(v: Any = "default"): String = s"called with parameter '$v'"

および Option val opt: Option[String]。オプション値 (定義されている場合) またはデフォルト パラメータを指定してこのメ​​ソッドを呼び出す方法は? つまり、明らかな解決策にもかかわらず

val result = if (opt.isDefined)
               from.here.to.foo(opt.get)
             else
               from.here.to.foo()

(おそらく長い)オブジェクトチェーンでメソッドを2回入力する必要がありますか?複数のオプション/デフォルトパラメータがあることは言うまでもありません...


私が思いつくことができるのは、役に立たないヘルパーだけです

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

しかし、高次関数でデフォルトのパラメーターについて言及できない場合...それだけです。メソッドのオーバーロードが同じ問題を引き起こすJavaの悪い昔を思い出します。

4

3 に答える 3

8

値が 1 つの場所でオプションであるという 2 つの概念、つまりオプションのパラメーターと を使用しているようです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"))

しかし、s を使用するとうまく機能します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)
于 2016-06-10T15:31:44.967 に答える
2

大きすぎてコメントに収まらない@Ł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するのは、メソッドのパラメーターの型としてのみ表示される必要があるため、予期しない場所で変換がトリガーされないことです。

于 2016-06-10T17:35:40.550 に答える
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 を一致させる必要があります。これは、メソッドが非Optionパラメーターを想定しているためです。

val optOrDefault = opt getOrElse "default"
foo(optOrDefault)
于 2016-06-10T15:33:21.340 に答える