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] Pascal's Triangle 杨辉三角

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Retur ...

  2. HTTPf服务器(3)

    功能完整的HTTP服务器 导语 这个一个功能完备的HTTP服务器.它可以提供一个完整的文档输,包括图像,applet,HTML文件,文本文件.它与SingleFileHttpServer非常相似,只不 ...

  3. 结构体内嵌函数指针实现C语言面向对象

    结构体内嵌函数指针 #include<stdio.h> void say(int age) { printf("我%d岁了\n",age); } struct stud ...

  4. MSSQLSERVER

    create database test--创建数据库zh use test --打开数据库 go--执行 create table tab--创建表 ( UserName ),--创建字符串类型的字 ...

  5. Python后台分页删除编辑查询

    「POST 数据」通常指 POST 时 body 中的数据.而 QueryString (URL)中也有可以带参数(通常是 GET 时的参数).如果 POST 时同时存在 QueryString 和 ...

  6. Reactjs+Webpack+es2015 入门HelloWord(一)

    链接,自己很久前总结的blog. https://my.oschina.net/tangyuanyu/blog/730265

  7. MATLAB的三维散点图

    MATLAB中三维散点图函数为scatter3(x,y,z) 三维火柴图为stem3(x,y,z)

  8. [个人论文]一种基于GPU并行计算的MD5密码解密方法

    求轻喷... [顺便get一份LaTeX论文模板....还是XeLaTex好用.珍爱生命远离CJK http://files.cnblogs.com/files/pdev/paper.zip

  9. 统一的Json组件和csv下载组件

    java-web-common java-web-common Json组件 目标和用途 规范Json接口格式 Controller中一律返回Java object,组件将自动转换数据格式,满足Jso ...

  10. js取当前周几

    纯javascript取当前周几 var dayNames = new Array("星期天","星期一","星期二","星期三& ...