2016-06-10 6 views
3

저는 스칼라에 대해 다소 새로운 것으로, 나를 괴롭히는 작은 문제를 발견했습니다. 의 기본 매개 변수스칼라에서 옵션 값 또는 기본 매개 변수를 사용하는 메서드 호출

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

과 옵션 val opt: Option[String] 몇 가지 방법이 있다고 가정 해 봅시다. 옵션 값 (정의 된 경우) 또는 기본 매개 변수 중 하나를 사용하여이 메서드를 호출하는 방법? I 명백한 용액

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를 사용하여 나쁜 옛날을 생각 나게합니다.

답변

3

두 매개 변수의 개념을 한 곳에서 선택적으로 사용할 수 있습니다 (예 : 선택적 매개 변수 및 Option). 그들은 함께 잘 노는 것을 좋아하지 않으며, 단지 하나만 사용하는 것이 좋습니다.

항상 Option 값을 메서드에 전달하거나 아무 값도 전달하지 않으면 Option을 수락하도록 함수를 변경하는 것이 좋습니다. 당신은 여전히 ​​기본 매개 변수를 원한다면

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

당신은 그러나 당신이 예를 들어, 일반 전화를 할 때 Some로 매개 변수를 포장 할 필요

def foo(v: Option[String] = None) 

이러한 접근 방식에 서명을 변경할 수 있습니다

foo(Some("regular param")) 

그러나 Option을 사용하면 잘 작동합니다. easly 선택적 매개 변수를 더 추가 할 수 있습니다. 여기

당신은 또한 당신이 Some을 생략 할 것이라고, Any에서 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 

입니다

implicit def any2option[A](e: A): Option[A] = Some(e) 
+0

동일한 의미의 일부를 유지하려면이 경우 "기본"매개 변수를 '없음'으로 설정할 수도 있습니다. – wheaties

+0

그래, 나도 알아 냈어. 그 대답은 진행중인 작업이었습니다 : p –

+0

나는이 방법을 손대지 못하게 할 수있는 해결책을 기대 했었습니다. 그것은 라이브러리의 일부가 될 수 있고 도달 할 수 없었을 것입니다. 그리고 매개 변수를 확인하면 먼저 기능 스타일이 손상됩니다. 그러나 아직도 멋지다! – ABika

0

Option에 정의 된 map 함수를 사용하여 내부에 래핑 된 값이 정의 된 경우 변환 할 수 있습니다. 이것은 다음과 같습니다 : 그것은 전에 None 인 경우

opt.map(foo) 
// same as 
opt.map(x => foo(x)) 

None 일부 값이 내부에 있다면 어느 쪽 Option[String]을 돌아가거나 것입니다.여기

는 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 

편집 : 방법은 기대하기 때문에

가 기본값을 호출하려면, 당신은 전화하기 전에 옵션과 일치해야합니다 non Option 매개 변수.

val optOrDefault = opt getOrElse "default" 
foo(optOrDefault) 
+0

나는 OP가'Option'이 비어있을 때''default ''매개 변수로 호출하는 것을보고 싶습니다. 이것은'opt map foo getOrElse foo()'를 필요로 할 것인데, 이것은 약간 더 뛰어나지 만,'foo'를 두 번 타이핑 할 필요가 있고 더 많은 선택적 매개 변수로 확장되지 않습니다. –

+0

흠, 당신 말이 맞을 수도 있습니다. 나는 내 대답을 연장 할 것이다, 고마워. –

1

약간의 확장에 @ 코멘트에 맞게 너무 커서의 Łukasz의 대답 : 당신은 특수 목적 유형을 작성하여 위험 any2option없이 Some에 존재하는 매개 변수를 포장하는 것을 방지 할 수 있습니다

:

를 이 안전하게 무엇
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은 오직, 메소드 매개 변수 유형으로 표시해야한다는 것입니다.

관련 문제