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的更多相关文章

  1. C# 6.0 (C# vNext) 新功能之:Null-Conditional Operator(转)

    Null-Conditional Operator 也叫 Null propagating operator 也叫 Safe Navigation Operator 看名字,应该就有点概念了.如果还不 ...

  2. coffeescript 1.8.0 documents

    CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque ...

  3. how to use coffee script

    TABLE OF CONTENTS TRY COFFEESCRIPT ANNOTATED SOURCE CoffeeScript is a little language that compiles ...

  4. coffeescript 1.6.3使用帮助

    CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque ...

  5. CoffeeScript 更优美的Javascript

    CoffeeScript 是一门编译到 JavaScript 的小巧语言. 在 Java 般笨拙的外表下, JavaScript 其实有着一颗华丽的心脏. CoffeeScript 尝试用简洁的方式展 ...

  6. groovy-运算符

    算术和条件运算符 Groovy支”!”操作符,例如: 1 def expression = false 2 assert !expression 基于集合的运算符: Spread Operator ( ...

  7. Scala Option类型

    转载自: Scala 初学者指南, 这里有一系列很棒的文章 类型 Option 可能你已经见过它在 Map API 中的使用:在实现自己的提取器时,我们也用过它, 然而,它还需要更多的解释. 你可能会 ...

  8. Spring生态研习【二】:SpEL(Spring Expression Language)

    1. SpEL功能简介 它是spring生态里面的一个功能强大的描述语言,支在在运行期间对象图里面的数据查询和数据操作.语法和标准的EL一样,但是支持一些额外的功能特性,最显著的就是方法调用以及基本字 ...

  9. Spring框架文档与API(4.3.6版本)

    http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Table of Contents I ...

随机推荐

  1. [LeetCode] Binary Watch 二进制表

    A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom ...

  2. [LeetCode] Implement strStr() 实现strStr()函数

    Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...

  3. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

  4. 一个c#的输入框函数

    private static string InputBox(string Caption, string Hint, string Default) { Form InputForm = new F ...

  5. Java jdbc访问sqlserver,oracle数据库

    1.JDBC访问Oracle数据库 public class Jdbc_Oracle { // 静态代码块,只会执行一次,类似C#静态构造方法 static { try { // 加载数据库驱动一次 ...

  6. 如何使用PullToRefresh

    这里有详解 PullToRefresh使用详解(一)--构建下拉刷新的listView PullToRefresh使用详解(二)---重写BaseAdapter实现复杂XML下拉刷新 PullToRe ...

  7. 在SpringMVC中使用@SessionAttributes和@ModelAttribute将数据存储在session域中

    今天在我的springMVC项目--图书管理系统中,希望在登录时将登录的Users存在session中,开始是准备在controller中使用Servlet API中的对象,可是一直无法引用,不知道为 ...

  8. jsp编码过程

    pageEncoding是jsp文件本身的编码 contentType的charset是指浏览器到服务器发送时使用的编码:以及服务器返回到浏览器使用的编码 JSP要经过三次的“编码” 第一阶段会用JS ...

  9. bash的管道符与重定向

    管道符"|"可以用来将前面的程序的标准输出stdout(=1)重定向到后一个程序的stdin(=0),但是忽略了stderr. 在bash中使用2>&1 可以表示将s ...

  10. MQTT开发笔记之《安全传输-自问自答》

    Mosquito使用SSL/TLS进行安全通信时的使用方法:http://www.it165.net/pro/html/201404/12615.htmljava版mosquitto客户端使用SSL功 ...