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 ...
随机推荐
- [LeetCode] Number of Connected Components in an Undirected Graph 无向图中的连通区域的个数
Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...
- [LeetCode] Best Time to Buy and Sell Stock IV 买卖股票的最佳时间之四
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- 基于ionic+angulajs的混合开发实现地铁APP
基于ionic+angulajs的混合开发实现地铁APP 注:本博文为博主原创,转载时请注明出处. 项目源码地址:https://github.com/zhangxy1035/SubwayMap 一. ...
- Js数组
参考:http://www.w3school.com.cn/jsref/jsref_obj_array.asp 一.数组定义 1. var arr= [1,2,3]; 2. var arr= ne ...
- insmod模块的几种常见错误
1. 与内核版本不一致 嵌入式开发时,模块编译时需要制定内核的路径,内核的版本信息会加入到模块文件中,如果目标板上运行的内核与模块中包含的内核版本对不上,加载就会出错,报如下错误: insmod i ...
- 【BZOJ 3993】【SDOI 2015】星际战争
http://www.lydsy.com/JudgeOnline/problem.php?id=3993 调了好长时间啊 这道题设时间为time,那么对于m个武器从S向这m个点连容量为time*Bi的 ...
- orcle函数的使用,及其调用
CREATE OR REPLACE Function getBdateT( D_Build date, Q_Date date) return Date as D_Return Date; /*返回的 ...
- Apache报错信息之Invalid command 'Order', perhaps misspelled or defined by a module not included in the server config
今天配置开启Apache虚拟主机时, 然后日志报错提示: Invalid command 'Order', perhaps misspelled or defined by a module not ...
- jQuery-DataTables相关的网址
DataTables 有没有觉得这张图的数据很熟悉,对,他们都是copy来的. 之前用了一个bootstrap的框架,写那个框架的老师,有点抠门,把很多js都合在了一起,不知道怎么去自定义自己的东西, ...
- apache.commons.compress 压缩,解压
最近在一个前辈的指引下,开始研究apache.commons.都是网上找的,而且不会中文乱码,而且还可以在压缩包里面加一层文件夹 package my.test; import java.io.Buf ...