[БЕЗ_ЗВУКА] [МУЗЫКА] [МУЗЫКА] Напоследок давайте чуть более подробно рассмотрим то, что такое null и как с ним работать. null — это специальное значение, которое означает отсутствие обычного объекта. Но так как Котлин, как и природа, не терпит пустоты, работать с null просто так не получится. Если вы попробуете присвоить null в переменную типа int, например, то компилятор выдаст вам ошибку типизации. Все дело в том, что значение null является допустимым только для специальных типов, которые могут его содержать — так называемых nullable типов. Все типы, с которыми мы работали до этого момента, были non-nullable или не могли содержать null. Для того чтобы сделать из обычного non-nullable типа nullable, достаточно приписать к нему знак вопроса. Например, nullable версия int — это int с вопросом. Знак вопроса будто бы говорит: я не уверен, будет ли здесь обычный int или же null. Есть ли еще какая-либо разница между int и int с вопросом, кроме того, что в одном из них может храниться null? Да, разница есть и весьма существенная. Многие обычные операции нельзя выполнить просто так над nullable типом именно потому, что он может содержать в себе null. Представим, что мы хотим сложить два int с вопросом и не знаем об этой особенности языка Котлин. Такой код, который бы работал для обычных int'ов, не компилируется для int с вопросом аж с двумя ошибками, суть которых заключается в предупреждении: здесь может быть null, а я не знаю, как сложить что-то с чем-то, чего может не быть. Для подобных ситуаций в Котлине есть специальные безопасные операции и операторы, учитывающие возможность появления null в типах с вопросами. Одним из таких операторов является оператор Элвис-оператор?:, названный так в честь схожести с прической короля рок-н-ролла Элвиса Пресли. Работает он следующим образом: выражение a? : value возвращает a в случае, если оно не равно null, и value в противном случае. Это самое value служит значением по умолчанию в случае, если a нет, то есть оно содержит null. Для нашего примера со сложением мы, например, можем считать, что отсутствующее число равно нулю. Еще один безопасный оператор — это оператор безопасного вызова вопрос точка. С его помощью можно безопасно вызывать функции над типами с вопросом. Выражение a?.foo() вызывает функцию foo над получателем в случае, если он не равен null. Если же a = null, то вместо вызова функции сразу вернется итоговый null. Представим, что мы хотим где-то в коде сложить все числа в каком-то nullable списке. Сделать это можно вот так, при помощи нашего оператора вопрос точка. Однако следует помнить, что тип у подобного выражения int с вопросом, потому что в итоге может вернуться null. И если бы мы, например, хотели вернуть такую сумму из функции с типом int без вопроса, то нам бы пришлось исправить тип при помощи Элвис-оператора. Третий оператор, о котором надо поговорить, но который не является безопасным, это оператор два восклицательный знака, или два «восклицака». Смысл этого оператора крайне прост — убрать вопрос. То есть сделать из nullable типа non-nullable тип. Для выражения a!! если a имеет нормальное значение, то операция завершится успешно и итоговый тип будет non-nullable. А вот если в a хранится null, то в данном месте произойдет ошибка NullPointerException. Именно поэтому оператор !! является небезопасным, и использовать его следует только тогда, когда вы уверены в том, что выражение не содержит null. Пусть мы пытаемся обработать, например, одно из значений в ассоциативном массиве следующим образом. Мы, конечно, проверили значение на null в if, но в следующей строчке считается, что map[key] тут все же может вернуть null, и выдается ошибка компиляции. Если мы считаем, что такого произойти никогда не может, то можно исправить ситуацию при помощи двух восклицательных знаков. Те из вас, кто что-то запомнили, могут спросить: подождите, в самом начале этого урока мы делали ровно то же самое, но никакого оператора !! писать нам не пришлось. Для тех, кто запамятовал, о чем идет речь, мы говорим о нашей функции shoppingListCost. В чем тут дело? Дело в такой штуке, как умное привидение типов, или смарт-касты. Компилятор Котлина увидел, что мы проверили на неравенство null неизменяемые значения itemCost, и помог нам путем стирания знака вопроса там, где null встретиться не может, а именно внутри тела if. Если присмотреться, можно увидеть, что подобные ситуации специальным образом подсвечиваются в редакторе кода. А почему это не работает для map[key]? Все просто: это выражение не является гарантированно неизменяемым. Для того чтобы код оставался безопасным, компилятор не делает никаких предположений и оставляет тип таким, какой он есть — типом с вопросом. А дальше, если вы уверены в том, что значение неизменяемое, вы можете применить оператор !! самостоятельно. Подводя итоги, можно запомнить следующие правила работы с nullable типами: если у вас есть осмысленное значение по умолчанию для вашего выражения или вашего случая, то применяйте Элвис-оператор. Если вы хотите вызвать функцию над типом с вопросом, оператор безопасного вызова — это ваш выбор. Если у вас ни то, ни другое и вы сомневаетесь, есть ли там null или нет, проверьте выражение на равенство null в if или в a и доверьтесь смарт-кастам. Если же вы уверены, что на самом деле null там никогда не может быть, тогда и только тогда можно применять оператор два восклицательных знака. Конечно, эти правила не абсолютная истина, и рано или поздно вы столкнетесь с ситуациями, когда они не работают. Но я практически уверен, что к тому моменту вы будете разбираться и в языке Котлин, и в программировании достаточно хорошо, чтобы справиться с ними самостоятельно. До встречи. [БЕЗ_ЗВУКА]