The Safe Navigation Operator (&.) in Ruby
The most interesting addition to Ruby 2.3.0 is the Safe Navigation Operator(&.). A similar operator has been present in C# and Groovy for a long time with a slightly different syntax - ?.. So what does it do?
Scenario
Imagine you have an account that has an owner and you want to get theowner’s address. If you want to be safe and not risk a Nil error you would write something like the following:
if account && account.owner && account.owner.address
...
end
This is really verbose and annoying to type. ActiveSupport includes the trymethod which has a similar behaviour (but with few key differences that will be discussed later):
if account.try(:owner).try(:address)
...
end
It accomplishes the same thing - it either returns the address or nil if some value along the chain is nil. The first example may also return false if for example the owner is set to false.
Using &.
We can rewrite the previous example using the safe navigation operator:
account&.owner&.address
The syntax is a bit awkward but I guess we will have to deal with it because it does make the code more compact.
More examples
Let’s compare all three approaches in more detail.
account = Account.new(owner: nil) # account without an owner
account.owner.address
# => NoMethodError: undefined method `address' for nil:NilClass
account && account.owner && account.owner.address
# => nil
account.try(:owner).try(:address)
# => nil
account&.owner&.address
# => nil
No surprises so far. What if owner is false (unlikely but not impossible in the exciting world of shitty code)?
account = Account.new(owner: false)
account.owner.address
# => NoMethodError: undefined method `address' for false:FalseClass `
account && account.owner && account.owner.address
# => false
account.try(:owner).try(:address)
# => nil
account&.owner&.address
# => undefined method `address' for false:FalseClass`
Here comes the first surprise - the &. syntax only skips nil but recognizesfalse! It is not exactly equivalent to the s1 && s1.s2 && s1.s2.s3 syntax.
What if the owner is present but doesn’t respond to address?
account = Account.new(owner: Object.new)
account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>
account && account.owner && account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
account.try(:owner).try(:address)
# => nil
account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
Oops, the try method doesn’t check if the receiver responds to the given symbol. This is why it’s always better to use the stricter version of try -try!:
account.try!(:owner).try!(:address)
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
Pitfalls
As Joeri Samson pointed out in the comments, this section is actually wrong - I mistakenly used ?. instead of &.. But I still think that the last example is confusing and nil&.nil? should return true.
Be careful when using the &. operator and checking for nil values. Consider the following example:
nil.nil?
# => true
nil?.nil?
# => false
nil&.nil?
# => nil
Array#dig and Hash#dig
The #dig method is, in my opinion, the most useful feature in this version. No longer do we have to write abominations like the following:
address = params[:account].try(:[], :owner).try(:[], :address)
# or
address = params[:account].fetch(:owner) .fetch(:address)
You can now simply use Hash#dig and accomplish the same thing:
address = params.dig(:account, :owner, :address)
Final words
I really dislike dealing with nil values in dynamic languages and think the addition of the safe operator and the digmethods is really neat. Note that Ruby 2.3.0 is still not released and some things might change in the final version.
The Safe Navigation Operator (&.) in Ruby的更多相关文章
- C# 6.0 (C# vNext) 新功能之:Null-Conditional Operator(转)
Null-Conditional Operator 也叫 Null propagating operator 也叫 Safe Navigation Operator 看名字,应该就有点概念了.如果还不 ...
- coffeescript 1.8.0 documents
CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque ...
- how to use coffee script
TABLE OF CONTENTS TRY COFFEESCRIPT ANNOTATED SOURCE CoffeeScript is a little language that compiles ...
- coffeescript 1.6.3使用帮助
CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque ...
- CoffeeScript 更优美的Javascript
CoffeeScript 是一门编译到 JavaScript 的小巧语言. 在 Java 般笨拙的外表下, JavaScript 其实有着一颗华丽的心脏. CoffeeScript 尝试用简洁的方式展 ...
- groovy-运算符
算术和条件运算符 Groovy支”!”操作符,例如: 1 def expression = false 2 assert !expression 基于集合的运算符: Spread Operator ( ...
- Scala Option类型
转载自: Scala 初学者指南, 这里有一系列很棒的文章 类型 Option 可能你已经见过它在 Map API 中的使用:在实现自己的提取器时,我们也用过它, 然而,它还需要更多的解释. 你可能会 ...
- Spring生态研习【二】:SpEL(Spring Expression Language)
1. SpEL功能简介 它是spring生态里面的一个功能强大的描述语言,支在在运行期间对象图里面的数据查询和数据操作.语法和标准的EL一样,但是支持一些额外的功能特性,最显著的就是方法调用以及基本字 ...
- Spring框架文档与API(4.3.6版本)
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Table of Contents I ...
随机推荐
- CentOS 配置MySQL允许远程登录
Mysql为了安全性,在默认情况下用户只允许在本地登录,可是在有此情况下,还是需要使用用户进行远程连接,因此为了使其可以远程需要进行如下操作: 一.允许root用户在任何地方进行远程登录,并具有所有库 ...
- [LeetCode] Decode String 解码字符串
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...
- MongoDBDao 工具类(包含分页取数据)
mongdb工具类 package e16wifi.statistic.com.mongodb; import java.util.ArrayList; import java.util.List; ...
- ActiveMQ与spring集成实现Queue模式
ActiveMQ可以和spring很好的集成,下面我们来看看,如何做个集成的demo. (1)pom.xml引入相关jar <!-- spring相关 begin --> <depe ...
- xss篇-本着就了解安全本质的想法,尽可能的用通俗易懂的语言去解释安全漏洞问题
前言 最早接触安全也是从xss攻击和sql注入攻击开始的. 0x01 跨站脚本攻击漏洞(XSS),是客户端脚本安全中的头号大敌,owasp top10 屡居榜首,由于攻击手法较多,开发者水平不一 ...
- Podfile使用说明
什么是Podfile ? CocoaPods是用ruby实现的,因此Podfile文件的语法就是ruby的语法.podfile是一个说明文件,用以描述管理一个或者多个Xcode project的tar ...
- Django进阶(二)
Template 之前的好多HTML文件中都包含类似"{{ }}"."{% %}",其实他们都是模板语言,模板本质上是HTML,但是夹杂了一些变量和标签,可以方 ...
- 贝赛尔曲线UIBezierPath
使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中.此类是Core Graphics框架关于path的一个封装.使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线 ...
- 利用django创建一个投票网站(四)
创建你的第一个 Django 项目, 第四部分 这一篇从第三部分(zh)结尾的地方继续讲起.我们将继续编写投票应用,专注于简单的表单处理并且精简我们的代码. 编写一个简单的表单 让我们更新一下在上一个 ...
- Beta阶段第八次Scrum Meeting
情况简述 BETA阶段第八次Scrum Meeting 敏捷开发起始时间 2016/12/21 00:00 敏捷开发终止时间 2016/12/22 00:00 会议基本内容摘要 deadline临近 ...