《Effective Ruby:改善Ruby程序的48条建议》一第9条:提防Ruby最棘手的解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

本节书摘来自华章出版社《Effective Ruby:改善Ruby程序的48条建议》一书中的第2章,第2.4节,作者 [美]彼得 J.琼斯(Peter J. Jones),更多章节内容可以访问云栖社区“华章计算机”公众号查看

第9条:提防Ruby最棘手的解析

说到命名规则,Ruby给了我们很大的自由。肃然不像Lisp那样的语言一样自由,但Ruby允许我们在方法末尾使用三个字母数字以外的符号:“?”、“!”和“=”。三个字符中的两个具有纯粹的美感,而另一个在Ruby中有特殊的含义。

如你所知,以问号结束的方法名既不会改变任何事情,也不会使Ruby对它特殊对待。这仅仅是一个为Ruby程序员所接受的命名惯例,以此来说明方法将返回一个布尔值。(要知道什么是Ruby中的布尔值,请参见第1条。)这个命名惯例并不是强制的,并且以“?”结尾的方法仍然可以返回你想要的任何类型的值。感叹号也是类似的,如果有所不同,也只是模糊一点。感叹号常常意味着方法会改变接收者,也可以是对你的示警,表示存在潜在的有害行为。这两种情况都是Ruby程序员指南中不提倡的。以等号结尾的方法则完全不同。
以“=”结尾的方法将变为setter方法,并允许你使用漂亮的语法来调用它。典型场景是,这类方法接受一个参数,改变一些内部状态,并返回它们的参数。这意味着setter方法也能被用作左值(赋值语句的左侧部分)。
image

即使从技术上讲“=”是方法名的一部分,Ruby却允许我们在等号和方法名的其他部分之间输入空格。这看似是变量赋值,但实质上仅仅是一个普通的方法调用。当你加上括号并去掉空格时你会更清楚地看到这一点。
image

你可能不曾亲手定义过这些setter方法,但你一定间接地定义过。因为Ruby有一些帮助方法能帮我们做这个事情。attr_writer和attr_accessor都像之前的例子一样定义了类似value=这样的setter方法。这样的迂回可能会让你有点困惑,这也是我提起它们的原因。只要你记住这些帮助方法做的事情以及接下来的建议,任何困难都不是问题。
说到困难,我们得看看赋值和setter之间的区别。由于setter方法的调用看似变量赋值,因此很容易混淆它们。看下面这个例子:
image

把initialize方法体中的内容当作对counter=方法的调用也不是毫无道理,这也是很多人所假设的。但这当然是不对的,那只是个简单的变量赋值呀。initialize方法创建了一个新的局部变量counter,并将其赋值为0,然后又在作用域结束的时候丢弃了对这个变量的引用。当你仔细思考,会发现这显然不是我们想做的。(如果你像第5条建议的那样启用了警告,Ruby将会在出现这个错误时提醒你。)
Ruby在对变量赋值和对setter方法调用时的解析是有区别的。区别在于,Ruby调用setter方法时要求存在一个显式接收者。为了调用setter方法,而非创建一个变量,你需要预先指定方法名的接收者。因此,在实例方法中调用方法counter=,你需要使用self充当这个接收者。

通过使用self作为接收者,Ruby将正确地解析你的代码并调用counter=这个setter方法,而非创建一个新的变量。你可能会想,如果在调用方法时在等号和方法名的其他部分间不加等号,并用括号包住参数也许可以避免使用self(即,counter=(0)),然而事与愿违,这是无效的。我们在这里被迫显式地使用self作为接收者,但这导致了另一个问题。
被解析规则坑过的程序员倾向于在它们的代码中过分使用不必要的self接收者,这会使代码显得凌乱。在每个方法调用前都加上self从技术角度来说没有问题,但显然它降低了代码的可读性。这显然是Ruby程序员中普遍存在的代码的坏味道。看看你能否在下面的代码中找到无须使用self的地方:
image

显然,full方法中的self是冗余的。由于没有调用setter方法,你可以安全地移除self并依靠那些简单的解析规则。当Ruby遇到类似f?irst或last的标识符时,它会检查当前作用域中是否存在同名变量。如果不存在,它会把这个标识符作为方法名再次查找。在本例中,对于Name类里的两个属性,Ruby通过早先的attr_accessor找到了它们的getter方法。这里有另一个版本的full方法,与之前的方法做了相同的事情,但去除了噪音:
image

到此为止,你应该对setter方法的特殊性确信无疑了。如果不想碰到些惊喜,记得调用时指定一个接收者。但是千万别因此让它愚弄了你,并不是所有方法都需要接收者,尤其是在实例方法中调用时。对于每个其他类型的方法,如果没有显式指定方法接收者,Ruby将自动使用self作为接收者。
要点回顾
setter方法在调用时需要显式的接收者。没有接收者时,会被Ruby解析为变量赋值。
在实例方法中调用setter方法时,使用self作为接收者。
在调用非setter方法时,不需要显式指定接收者。换句话说,不要使用不必要的self,那会弄乱你的代码。

相关文章
|
4月前
|
SQL 安全 Windows
SQL安装程序规则错误解析与解决方案
在安装SQL Server时,用户可能会遇到安装程序规则错误的问题,这些错误通常与系统配置、权限设置、依赖项缺失或版本不兼容等因素有关
|
4月前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
73 0
|
4月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
111 0
|
5月前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与应用在软件开发的浩瀚海洋中,PHP以其独特的魅力和强大的功能吸引了无数开发者。作为一门历史悠久且广泛应用的编程语言,PHP不仅拥有丰富的内置函数和扩展库,还支持面向对象编程(OOP),为开发者提供了灵活而强大的工具集。在PHP的众多特性中,设计模式的应用尤为引人注目,它们如同精雕细琢的宝石,镶嵌在代码的肌理之中,让程序更加优雅、高效且易于维护。今天,我们就来深入探讨PHP中使用频率颇高的一种设计模式——策略模式。
本文旨在深入探讨PHP中的策略模式,从定义到实现,再到应用场景,全面剖析其在PHP编程中的应用价值。策略模式作为一种行为型设计模式,允许在运行时根据不同情况选择不同的算法或行为,极大地提高了代码的灵活性和可维护性。通过实例分析,本文将展示如何在PHP项目中有效利用策略模式来解决实际问题,并提升代码质量。
|
6月前
|
开发者 编解码
界面适应奥秘:从自适应布局到图片管理,Xamarin响应式设计全解析
【8月更文挑战第31天】在 Xamarin 的世界里,构建灵活且适应性强的界面是每位开发者的必修课。本文将带您探索 Xamarin 的响应式设计技巧,包括自适应布局、设备服务协商和高效图片管理,帮助您的应用在各种设备上表现出色。通过 Grid 和 StackLayout 实现弹性空间分配,利用 Device 类检测设备类型以加载最优布局,以及使用 Image 控件自动选择合适图片资源,让您轻松应对不同屏幕尺寸的挑战。掌握这些技巧,让您的应用在多变的市场中持续领先。
60 0
|
7月前
|
数据可视化 持续交付 开发工具
RAD技术解析:快速开发应用程序的秘诀
**快速应用开发(RAD)**是一种始于90年代的敏捷方法,旨在通过迭代原型和反馈加速高质量软件交付。由James Martin提出,它包括需求规划、界面设计、快速构建和持续优化四阶段,以提高质量、降低风险、增强灵活性、降低成本和提升客户满意度。工具如ZohoCreator支持RAD,通过可视化工具和低代码平台促进高效开发,实现快速迭代和市场适应,降低项目失败风险,提高用户满意度。
140 9
|
7月前
|
SQL 安全 数据库
Ruby on Rails 数据库迁移操作深度解析
【7月更文挑战第19天】Rails 的数据库迁移功能是一个强大的工具,它帮助开发者以版本控制的方式管理数据库结构的变更。通过遵循最佳实践,并合理利用 Rails 提供的迁移命令和方法,我们可以更加高效、安全地管理数据库结构,确保应用的稳定性和可扩展性。
|
6月前
|
存储 并行计算 API
ViperGPT解析:结合视觉输入与文本查询生成和执行程序
ViperGPT是一个创新的混合视觉和语言处理模型,通过生成和执行代码来解决视觉查询问题,具有高度模块化、灵活性和优秀的外部知识查询能力。
107 0
|
7月前
|
调度
【浅入浅出】Qt多线程机制解析:提升程序响应性与并发处理能力
在学习QT线程的时候我们首先要知道的是QT的主线程,也叫GUI线程,意如其名,也就是我们程序的最主要的一个线程,主要负责初始化界面并监听事件循环,并根据事件处理做出界面上的反馈。但是当我们只限于在一个主线程上书写逻辑时碰到了需要一直等待的事件该怎么办?它的加载必定会带着主界面的卡顿,这时候我们就要去使用多线程。
214 6
|
8月前
|
Java 程序员
程序技术好文:解析器组合子
程序技术好文:解析器组合子
63 1

推荐镜像

更多