На прошлой неделе я писал о некоторых крайних случаях правдоподобия в JavaScript. На этот раз у меня есть небольшая заметка об элегантной обработке нулевых/неопределенных значений.
null
— названный его изобретателем C.A.R. «ошибкой на миллиард долларов». Хоар — большинство программистов, вероятно, хорошо знакомы с этим (и почему это может быть классифицировано как ошибка!)
Наверняка мы все писали примерно такой код:
if(foo != null) { // Do something with foo }
Но что, если foo
— это объект с несколькими уровнями вложенных объектов? Вы, вероятно, согласитесь, что писать что-то вроде этого становится немного громоздко:
if(foo != null) { if(foo.bar != null) { if(foo.bar.baz != null) { // Now it's safe to use foo.bar.baz } } }
В некоторых более современных языках (Kotlin, JavaScript 2020, Swift и т. д.) есть поддержка так называемых «безопасных вызовов/необязательных цепочек», и выглядит это так:
x = foo?.bar?.baz?.doSomething()
?
указывает, что правая часть должна оцениваться только в том случае, если левая часть не равна null
. Однако если какая-либо часть этого выражения равна null
, то x
будет null
.
Что, если бы мы захотели указать, какое значение должно иметь x
в случае, если какая-либо из null
проверок не пройдена? Очевидно, мы могли бы добиться этого, проверив, является ли x
null
после оператора, а затем присвоив ему другое значение, но если бы мы хотели, чтобы x
было константой, это было бы невозможно.
Некоторые языки поддерживают тернарный оператор, поэтому вы можете сделать что-то вроде этого:
x = foo?.bar?.baz ? foo?.bar?.baz?.doSomething() : <fallback value>
На мой взгляд, это повторяется, а также подвержено ошибкам — если doSomething()
возвращает null
, то x
все еще может быть null
! Вы можете обойти это, поставив ?.doSomething()
перед ?
тернарного оператора, но уверены ли мы, что безопасно вызывать doSomething()
более одного раза? Это может иметь побочные эффекты, которые вносят тонкие ошибки в наш код или требуют больших ресурсов и снижают производительность нашего приложения.
Вместо этого я хотел бы предложить лучший способ — нулевой оператор объединения:
x = foo?.bar?.baz?.doSomething() ?? <fallback value>
Таким образом, x
все еще может быть константой, мы будем перехватывать любые возможные значения null
во всей цепочке и вызывать doSomething()
только один раз (максимум).
Теперь, если вы уловили это, почему я назвал это оператором объединения null(ish)? Это связано с тем, что в JavaScript необязательный оператор цепочки и оператор объединения null применяются ОБА к null
и undefined
. Аккуратно, да?
Я знал об этой концепции, работая в Kotlin, где этот функционал называется «оператор Элвиса». Он пишется как ?:
— что немного похоже на макушку головы Элвиса (глаза и его фирменная вьющаяся прическа) — плюс, в сообществе Kotlin мы можем помнить, что все, что происходит справа от оператора, происходит, когда « Элвис покинул здание» (т.е. если вы столкнулись с null
и оставили необязательную цепочку) И да, я знаю — иногда программисты могут быть настоящими кретинами. ;-)
Теперь, когда я работал в React Native с использованием TypeScript (который построен на основе JavaScript), я обнаружил, что эта функциональность также существует. Это привело меня к открытию того же понятия в Swift — «нулевого оператора объединения» (представленного ??
).
Все это к тому, что я думаю, что это действительно здорово, что все больше и больше современных языков программирования сходятся и поддерживают все больше похожих способов написания кода. У каждого языка всегда будут свои особенности (а также преимущества и недостатки), но я думаю, что мы становимся намного ближе к миру, в котором разработчики Android могут читать кодовую базу iOS и понимать, что происходит (не так было тогда, когда они еще были написаны). в Objective C), или традиционный веб-разработчик может работать над мобильным приложением (уже реальность благодаря таким технологиям, как React Native).
Знаете другие языки, которые поддерживают какой-либо вариант необязательного связывания/слияния нулей? Я хотел бы услышать от вас в комментариях!
Хотите работать со мной в замечательной команде цифровых продуктов Accenture? Мы нанимаем мобильных разработчиков, веб-разработчиков и больше!