2016-09-27 2 views
7

중 하나를 기본 인수 값을 지정하여 선택적 매개 변수를 표현하는 방법은 두 가지가 있습니다 :기본 인수 과부하 대, 때 사용할 코 틀린에

fun foo(parameter: Any, option: Boolean = false) { ... } 

또는 과부하 도입하여 :

fun foo(parameter: Any) = foo(parameter, false) 
fun foo(parameter: Any, option: Boolean) { ... } 

어느 상황에서 어느 쪽이 선호됩니까?

이러한 기능을 가진 소비자의 차이점은 무엇입니까?

+0

참고 : 같은 다른 언어 [C#을] (http://stackoverflow.com/questions/16789341/function-overloading-vs-optional-parameters) 또는 관련 비슷한 질문이 있지만 [VB.NET] (http://stackoverflow.com/questions/304389/function-overloading-vs-default-parameters-in-vb-net)이 질문은 Kotlin에만 해당됩니다. – Ilya

+0

과부하는 절대로 사용하지 마십시오. '@ JVMOverloads'가 Java에서 그들을 소비하는데 유용 할 수도 있습니다 – voddan

답변

9

다른 Kotlin 코드를 호출하는 Kotlin 코드에서 선택적 매개 변수는 오버로드를 사용하는 것보다 일반적인 경향이 있습니다. 선택적 매개 변수를 사용하면 기본 동작이됩니다. 궐석 한 값을 사용

특별한 경우 : 일반적인 관행으로

  • 또는 모르는 경우 - 오버라이드 (override) 이상 사용 기본 인수입니다.

  • 발신자가 기본값을 표시하려면 기본값을 사용하십시오. IDE 도구 설명 (, 즉 Intellij IDEA)에 표시되고 발신자에게 계약서의 일부로 적용되고 있음을 알립니다. 당신은 값이 xy 생략하는 경우 foo()를 호출하면 일부 값을 기본값으로하는 다음의 스크린 샷에서 볼 수 있습니다

    enter image description here

    기능 과부하와 같은 일을하고있는 것은이 유용한 정보를 숨 깁니다 반면 단지 훨씬 더를 제공합니다 지저분 : 기본값을 사용

    enter image description here

  • 두 가지 기능, 지정된 모든 파라미터와 다른 제 한 바이트 코드의 생성을 야기 at는 누락 된 매개 변수를 검사하여 기본값을 적용 할 수있는 브리지 기능입니다. 기본 매개 변수의 수에 관계없이 항상 두 가지 기능 만 있습니다. 따라서 총 기능 수가 제한된 환경 (, 즉 Android)에서는 동일한 작업을 수행하는 데 더 많은 오버로드가 발생하지 않고이 두 가지 기능 만 사용하는 것이 좋습니다.

는 기본 인자 값을 사용하고 싶지 않을 수도 케이스 :

  • 다른 JVM의 언어가 하나가 명시 적으로 오버로드를 사용하는 데 필요한 채무 불이행 값을 사용할 수 있도록하려는 경우 또는

    기본값이있는 모든 매개 변수에 대해 하나의 추가 오버로드가 생성되며이 매개 변수에는 다음과 같은 매개 변수가 있습니다. d 매개 변수 목록의 오른쪽에있는 모든 매개 변수가 제거되었습니다.

  • 라이브러리의 이전 버전이 있고 이진 API 호환성을 위해 기본 매개 변수를 추가하면 기존 컴파일 된 코드의 호환성이 떨어질 수 있지만 과부하는 추가하지 않을 수 있습니다.

  • 당신은 이전의 기존 기능이 있습니다

    fun foo() = ... 
    

    을 그리고 당신은 그 함수의 서명을 유지해야하지만 당신은 또한 동일한 서명 만 추가 옵션 매개 변수를 사용하여 다른를 추가 할 :

    fun foo() = ... 
    fun foo(x: Int = 5) = ... // never can be called using default value 
    

    두 번째 버전에서는 리플렉션 (callBy 제외)을 제외한 기본값을 사용할 수 없습니다. 대신 매개 변수없이 모두 foo() 호출은 여전히 ​​함수의 첫 번째 버전을 호출합니다. 그래서 대신 기본 않고 별개의 오버로드를 사용해야하거나 기능의 사용자가 혼동됩니다

    fun foo() = ... 
    fun foo(x: Int) = ... 
    
  • 을 당신은 함께 이해가되지 않을 수 있습니다 인수를, 따라서 과부하는 의미있는 조정 세트로 그룹 매개 변수를 허용 .

  • 기본값이있는 메소드를 호출하면 누락 된 값을 확인하고 기본값을 적용한 다음 실제 메소드로 호출을 전달하는 또 다른 단계가 필요합니다. 따라서 성능이 제한된 환경 (, 즉 안드로이드, 메서드 호출에 10 억 개의 반복 루프가 포함 된)이 추가 검사가 바람직하지 않을 수 있습니다. 프로파일 링에서 문제점을 발견하지 못하면 상상의 문제 일 수도 있고 JVM에 의해 인라인 될 수도 있으며 전혀 영향을 미치지 않을 수도 있습니다. 걱정하기 전에 먼저 측정하십시오. C# answer for this similar question 존경을의 경우

    당신이 다른 언어에서 이것에 대해 일반적으로 인수를 읽고 ...

    • :

    정말 두 경우 모두를 지원하지 않는 케이스 Jon Skeet은 빌드간에 변경이 가능하고 문제가 발생할 수있는 경우 기본값을 사용하여주의해야한다고 언급합니다. C#에서는 기본값이 호출 사이트에 있지만 Kotlin에서는 인라인되지 않은 함수의 경우 호출되는 (브리지) 함수 내부에 있습니다. 따라서 Kotlin의 경우 값의 숨김 및 명시 적 기본값 변경에 대해 동일한 영향을 미치며이 인수는 결정에 영향을 미치지 않습니다.

  • 또한 팀 구성원이 기본 인수의 사용에 대해 반대 견해를 가지고 있다면 사용하지 않을 수도 있습니다. Kotlin은 핵심 언어 기능이며 1.0 이전부터 표준 라이브러리에서 사용 되었기 때문에 Kotlin에 적용해서는 안되며 사용 제한에 대한 지원이 없습니다. 상대방 팀 구성원은 자신을 사용할 수 없게 만드는 확실한 경우가 아니라면 기본값으로 된 인수를 사용하도록 기본 설정해야합니다. C#에서 반면 그것은 그 언어의 라이프 사이클에 훨씬 나중에 도입 따라서의 기본 인자 값으로 함수가 있는지 코 틀린 컴파일하는 방법을 살펴 보자 더 "옵션 채택"

+0

Kotlin을 모르지만 foo()를 호출 할 때 X를 기본값으로 남겨 두면서 기본값이 아닌 값을 전달할 수 있습니까? 그렇지 않으면 코드의 여러 위치에서 X의 기본값을 복사해야하므로 문제가있는 것처럼 보입니다. –

+1

@BobBrinks 이것은 Kotlin 문서에서 분명히 다루어 져 있습니다. 다른 값이 아닌 일부 값을 전달할 수 있습니다. 매개 변수 목록의 정의 방법에 따라 정렬 된 매개 변수 또는 명명 된 매개 변수를 사용하면됩니다. –

3

의 감각을 가지고 있었다 된 방법 수의 차이. 대상 플랫폼에 따라 다를 수 있으므로 먼저 Kotlin에서 JVM을 살펴 보겠습니다.

  • 먼저 모든 인수는 호출 사이트에서 지정된 때 호출되고있는 foo(Ljava/lang/Object;Z)V입니다 : 다음 두 가지 방법이 생성되는 기능 fun foo(parameter: Any, option: Boolean = false)를 들어

    .

  • 둘째는 synthetic bridge foo$default(Ljava/lang/Object;ZILjava/lang/Object;)V입니다. 여기에는 실제로 전달 된 매개 변수를 지정하는 Int 마스크와 현재 사용되지 않는 Object 매개 변수가 있으며 향후 기본 인수가있는 수퍼 콜을 허용하기 위해 예약되어 있습니다.

호출 사이트에서 일부 인수가 생략 될 때이 브리지가 호출됩니다. 브릿지는 마스크를 분석하고 누락 된 인수에 대한 기본값을 제공 한 다음 모든 인수를 지정하는 첫 번째 메서드를 호출합니다.

함수에 @JvmOverloads 주석을 추가하면 각 인수 당 하나씩 기본값이있는 추가 오버로드가 생성됩니다. 이러한 모든 오버로드는 foo$default 브리지에 위임됩니다. foo 함수의 경우 다음과 같은 추가 과부하가 생성됩니다 : foo(Ljava/lang/Object;)V.

따라서 메서드의 카운트 관점에서 보면 함수에 기본값이있는 매개 변수가 하나 뿐인 상황에서 오버로드 나 기본값을 사용하더라도 상관없이 두 가지 방법이 있습니다. 그러나 둘 이상의 선택적 매개 변수가있는 경우 과부하 대신 기본값을 사용하면 메서드 생성 횟수가 줄어 듭니다.

2

매개 변수를 생략 할 때 함수 구현이 단순 해지면 오버로드를 선호 할 수 있습니다. ignoreCase를 사용하지 않는 두 번

compare(a, b)ignoreCase처럼라고
fun compare(v1: T, v2: T, ignoreCase: Boolean = false) = 
    if (ignoreCase) 
     internalCompareWithIgnoreCase(v1, v2) 
    else 
     internalCompare(v1, v2) 

생략, 당신이 실제로 지불 :

는 다음과 같은 예를 생각해 인수가 체크 및 기본 값을 대체하는 대신 생략하는 경우 첫 번째 두 번째는 compare의 본문에있는 ignoreCase을 확인한 후 해당 값을 기준으로 internalCompare으로 분기하는 것입니다.

과부하를 추가하면이 두 가지 확인 사항이 제거됩니다. 또한이 간단한 몸체를 가진 메소드는 JIT 컴파일러에 의해 인라인 될 가능성이 더 큽니다.

fun compare(v1: T, v2: T) = internalCompare(v1, v2)