2017-12-19 68 views
12

nullable 문자열 변수 ab이 있습니다. null을 할당 한 후 안전 호출 연산자를 통해 toUpperCase으로 호출하면 kotlin이 오류를 발생시킵니다.kotlin 안전 통화에서 과부하 해결 모호성 오류가 발생했습니다

fun main(args: Array<String>){ 
    var ab:String? = "hello" 
    ab = null 
    println(ab?.toUpperCase()) 
} 

Error:(6, 16)
Overload resolution ambiguity:
@InlineOnly public inline fun Char.toUpperCase(): Char defined in kotlin.text
@InlineOnly public inline fun String.toUpperCase(): String defined in kotlin.text

문제는 여기에 무엇입니까?

답변

2

확실하지는 않지만 스마트 캐스팅 (null 입력 가능 유형의 하위 유형 Nothing?)으로 인해 버그가있는 것 같습니다. 이 사람은 작동합니다

fun main(args: Array<String>) { 
    var ab: String? = "hello" 
    ab = makeNull() 
    println(ab?.toUpperCase()) 
} 

fun makeNull(): String? = null 

유일한 차이점을 : 컴파일러는 당신의 예에서 오류를 일으키는 것으로 보인다 직접 null 할당을 알 수 없습니다. 그러나 여전히, 당신도 아마 일해야합니다.

2

정말 버그 같아 보입니다. 유형 String?null을 할당하면 어떻게 든 사라 지므로 컴파일러에 String?을 명시 적으로 말해야합니다.

fun main(args: Array<String>){ 
    var ab: String? = "hello" 
    ab = null 
    println((ab as String?)?.toUpperCase()) // explicit cast 

    // ...or 

    println(ab?.let { it.toUpperCase() }) // use let 
} 
1

나는 이것이 Kotlin에서 사용하는 smart casts 때문일 것으로 생각합니다. 즉, 코 틀린 코드의 줄 끝에서 저를 추론 할 수있다 : - 나는 단순히 범위를 참조하고 변수 ab의 유형은 단순히 null

ab = null 

입니다 (이것은 당신이 코 틀린에 사용할 수있는 실제의 형태는 아니다 허용되는 값)가 아니며 String?이 아님 (즉, 은 없습니다)ab에는 String이 포함될 수 있습니다.

toUpperString() 확장 함수가 Char 및 String (Char? 또는 String?이 아닌)에만 정의되어 있다는 점을 감안할 때 선택할 수있는 방법이 없습니다.

다른 사용자가 제안한 답변 (예 : 명시 적으로 String으로 캐스팅?)을 참조하십시오. 그러나 이것은 확실히 나를위한 버그가 아닌 기능 (및 매우 유용한 기능)처럼 보입니다. 이 doc about smart-casts에 명시된 바와 같이

+1

"변수 ab 유형은 null입니다."null은 유형이 아닙니다! –

+0

"ToUpperString() 확장 함수가 Char 및 String (Char? 또는 String이 아닌)에만 정의되어 있다는 점을 감안할 때 선택할 방법이 없습니다." 안전한 호출 연산자가 사용되므로 toUpperString()이 null 인 경우 ab에 호출되지 않습니다. –

+0

"ab가 문자열을 포함 할 수있는 방법이 없습니다.)"null 할당 후에 ab = "hello2"를 할당하면 어떻게됩니까? 갑자기 문자열을 다시 포함하는 * 방법이 있습니다. –

5

:

x = y makes x of the type of y after the assignment

라인 ab = null 아마 스마트 캐스트 abNothing?합니다. ab is Nothing?을 확인하면 실제로는 true입니다. Nothing? 이후

var ab: String? = "hello" 
ab = null 
println(ab?.toUpperCase()) 
println(ab is Nothing?) // true 

이 (Char?String? 포함) 모든 유형의 하위 유형입니다, 당신이 Overload resolution ambiguity 오류가 발생하는 이유에 대해 설명합니다. 이 오류에 대한 해결책은 Willi Mentzel이 his answer에 언급 한 내용이며 toUpperCase()을 호출하기 전에 을 String 유형으로 캐스팅하는 것입니다.

//interface 
interface A {} 
interface B {} 

//extension function 
fun A.x() = 0 
fun B.x() = 0 

//implementing class 
class C : A, B {} 

C().x() //Overload resolution ambiguity 
(C() as A).x() //OK. Call A.x() 
(C() as B).x() //OK. Call B.x() 
+0

기다려, 'ab'가 이미 첫 줄에 Nullable String으로 정의되어 있지 않습니까? 그렇다면 String에 캐스트해야하는 이유는 무엇입니까? 필요한거야? – donfuxx

+0

@donfuxx'ab'의 타입은'Nothing?'으로 똑똑하고'Nothing?'은'String?'과'Char?'의 서브 타입입니다. 동시에, 수신기 함수'String'과'Char'로 선언 된 확장 함수'toUpperCase()'가 있습니다. 그래서 우리는 컴파일러에게'String'을 수신기로 사용하여 확장 함수를 호출하기를 원한다는 것을 말해야합니다. – BakaWaii

+0

신성한 암소, 그냥 디버거에서 질문의 코드를 밟았으며 'ab is Nothing?'이 참으로 평가되었습니다. 그래서 "똑똑한"캐스팅이 일어난 것 같아요.하지만 아마도 "멍청한"캐스팅이 더 좋은 이름이 될 것입니다 .- 나는이 답변을 분석하는데 도움이 되었기 때문에 이것을 다른 응답처럼 kotlin 버그로 보는 것을 선호하지만 여전히 엄지 손가락을 뽑습니다.) – donfuxx

1

나는 당신의 기능을 디 컴파일 내가 생각 :


설명 : 클래스가이 인터페이스를 구현하고 두 인터페이스가 동일한 서명의 확장 기능이있는 경우 는 이러한 종류의 오류가 발생합니다 순간 후 ab = null을 컴파일러는 스마트 캐스팅하여 null (ACONST_NULL)을 발생시킬 때마다 ab이됩니다. 그렇다면 null에는 유형이 없습니다. toUpperCase()의 수신자 유형을 추론 할 수 없습니다.

public final void main(@NotNull String[] args) { 
    Intrinsics.checkParameterIsNotNull(args, "args"); 
    String ab = "hello"; 
    ab = (String)null; 
    Object var3 = null; 
    System.out.println(var3); 
} 

그것은 코 틀린 팀에 의해 해결되어야하는 문제로 보인다 :

이는 코 틀린 바이트 코드에서 생성 된 자바 해당하는 코드입니다.

+0

참고 : 코드를 컴파일/디 컴파일 할 수 있도록'toUpperCase' 대신'toInt'를 사용했습니다 – crgarridos