иметь возможность компилировать / декомпилировать код

я есть строковая переменнаяab, Если я позвонюtoUpperCase через оператора безопасного вызова после того, как я назначил ему значение null, kotlin выдает ошибку.

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

Ошибка: (6, 16)
Неоднозначность разрешения перегрузки:
@InlineOnly общедоступное встроенное веселье Char.toUpperCase (): символ определен в kotlin.text
@InlineOnly общедоступное встроенное веселье String.toUpperCase (): строка, определенная в kotlin.text

В чем здесь проблема?

Ответы на вопрос(5)

Это действительно похоже на ошибку. Тип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
}

Я не уверен, но это кажется ошибкой из-за умного литьяNothing?, подтип каждого обнуляемого типа). Этот работает:

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

fun makeNull(): String? = null

Единственная разница: компилятор не знаетnull присваивание напрямую, что, по-видимому, вызывает ошибку в вашем примере Но, тем не менее, ваш, вероятно, тоже должен работать.

документ о смарт-бросках:

х = у делает х типа у после присваивания

Линияab = null наверное умные броскиab вNothing?, Если вы проверитеab is Nothing? да действительноtrue.

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

посколькуNothing? это подтип всех типов (в том числеChar? а такжеString?), это объясняет, почему вы получаетеOverload resolution ambiguity ошибка. Решением этой ошибки будет то, что упомянул Вилли Ментцель вего ответ, Кастингab к типуString перед звонкомtoUpperCase().

Примечания: Этот тип ошибки будет возникать, когда класс реализует два интерфейса, и оба интерфейса имеют функцию расширения с одинаковой сигнатурой:

//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()
 Kirill Rakhman21 дек. 2017 г., 13:43
@donfuxx Это очень сложный случай. Когда вы назначаетеnull что-то, а затем выполнить безопасный вызов? Вызов никогда не будет выполнен в любом случае. Во всяком случае, я бы предпочел, чтобы предупреждение компилятора было таким: «ab, как известно, имеет значение null, вызов никогда не будет выполнен».
 donfuxx19 дек. 2017 г., 17:35
Святая корова, только что пошла по коду вопроса в отладчике иab is Nothing? оценивается как правда. Так что "умное" приведение произошло, я думаю ... но, вероятно, "тупое" приведение было бы более подходящим именем ;-) Я предпочитаю видеть это как ошибку kotlin, как и другие ответы, но все же, поскольку этот ответ помог проанализировать: - )
 donfuxx19 дек. 2017 г., 17:12
Подожди, неab уже определен как Nullable String в первой строке? Так зачем приводить к String? быть необходимым?
 s1m0nw119 дек. 2017 г., 17:47
Хороший анализ, который имеет смысл
 BakaWaii19 дек. 2017 г., 17:22
@donfuxx Так как типab умно приведенNothing? а такжеNothing? это подтип обоихString? а такжеChar?, В то же время, есть функция расширенияtoUpperCase() заявлено с типом приемникаString а такжеChar, Итак, мы должны сообщить компилятору, что мы хотим вызвать функцию расширения сString как получатель.

Я считаю, что это связано сумные броски используется Kotlin. Другими словами, Котлин может вывести это после этой строки кода:

ab = null

тип переменнойab это простоnull (это не фактический тип, который вы можете использовать в Kotlin - я просто имею в виду диапазон допустимых значений), а неString? (другими словами, естьни за что ab может содержатьString).

Учитывая, что функция расширения toUpperString () определена только для Char и String (а не Char? Или String?), Между ними нет возможности выбирать.

Чтобы избежать такого поведения, посмотрите ответы, предложенные другими парнями (например, явное приведение к String?), Но это определенно выглядит как функция (и довольно полезная), а не как ошибка для меня.

 code_x38619 дек. 2017 г., 13:54
Да, компиляторможет быть в состоянии решить, что нет вызоваtoUpperCase() будет сделано в любом случае, так что он может полностью игнорировать все это. Тем не менее, разработчики Kotlin решили сделать эту проверку все же. Является ли это хорошим решением - вопрос личных предпочтений, и для меня кажется достаточно разумным сделать такую ​​проверку.
 Willi Mentzel19 дек. 2017 г., 13:35
«Учитывая, что функция расширения toUpperString () определена только для Char и String (а не Char? Или String?), Выбор между ними невозможен». используется оператор безопасного вызова, и, следовательно, toUpperString () никогда не вызывается для ab в случае, если он равен нулю.
 Willi Mentzel19 дек. 2017 г., 13:33
"тип переменной ab просто нулевой" null не является типом!
 Willi Mentzel19 дек. 2017 г., 13:42
«... нет способа, которым ab мог бы содержать String)», что если я назначу ab = "hello2" после нулевого присваивания. вдруг естьпрочь что он снова содержит строку.
 code_x38619 дек. 2017 г., 13:49
Да нетnull тип, который вы можете использовать, но вполне вероятно, что компилятор может использовать "вид"null тип снизу (в основном, представьте Typescript там, где его нельзя использоватьnull явно) при создании вывода типа. Конечно, это всего лишь предположение, но фактическое поведение довольно согласуется с этим предположением. Нам понадобится комментарий от кого-то из команды разработчиков Kotlin, чтобы уточнить, как на самом деле работают смарт-броски.

ab = null компилятор его умный вещает, ставяnull (ACONST_NULL) в каждом случаеab, Тогда какnull не имеет типа. вы не можете определить тип для получателяtoUpperCase().

Это эквивалентный Java-код, сгенерированный из байтового кода kotlin:

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

Это выглядит как проблема, которая должна быть решена командой kotlin.

 crgarridos19 дек. 2017 г., 18:06
Примечание: я использовалtoInt вместоtoUpperCase иметь возможность компилировать / декомпилировать код

Ваш ответ на вопрос