惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
V
V2EX
G
Google Developers Blog
F
Full Disclosure
Martin Fowler
Martin Fowler
宝玉的分享
宝玉的分享
H
Hacker News: Front Page
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
NISL@THU
NISL@THU
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
Hacker News - Newest:
Hacker News - Newest: "LLM"
A
About on SuperTechFans
The Cloudflare Blog
C
Cisco Blogs
D
DataBreaches.Net
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Vercel News
Vercel News
P
Privacy International News Feed
Microsoft Security Blog
Microsoft Security Blog
Help Net Security
Help Net Security
Recorded Future
Recorded Future
PCI Perspectives
PCI Perspectives
S
Schneier on Security
AI
AI
N
News | PayPal Newsroom
雷峰网
雷峰网
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
The Last Watchdog
The Last Watchdog
L
LINUX DO - 最新话题
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
S
Securelist
云风的 BLOG
云风的 BLOG
Stack Overflow Blog
Stack Overflow Blog
博客园_首页
AWS News Blog
AWS News Blog
TaoSecurity Blog
TaoSecurity Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 三生石上(FineUI控件)
C
CXSECURITY Database RSS Feed - CXSecurity.com
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Cloudbric
Cloudbric
C
Cybersecurity and Infrastructure Security Agency CISA
Project Zero
Project Zero
C
Check Point Blog
S
Security Affairs

胡涂说

当心流量别被 Agent 都吃了 当 AI 构建自己 阿嬷 ā mó Bun 要从 Zig 迁移到 Rust ? 好奇心周刊第25期: 如何让AI写好代码 好奇心周刊第24期: 关于AI编程的一些体会和设想 云何降伏其心 好奇心周刊第23期: Claude Code 氛围编程初体验 好奇心周刊第22期: 纳瓦尔谈人生 不确定性世界的生存策略 好奇心周刊第21期: 推理模型的构建与未来 好奇心周刊第20期: 从四个方面了解Palantir 周刊第19期: 一起学习 MCP 周刊第18期: 什么是理工科思维 周刊第17期: 如何构建智能体(Agent) 周刊第16期: Andrej Karpathy 讲 AI 读《毛泽东传》对个人的启发 周刊第15期:Nat Friedman 和 Derek Sivers 的自我介绍 周刊第14期:罗振宇和《罗辑思维》 我看《哪吒》 为什么写作? 心猿意马 从铁幕到硅幕 银弹飞过先锋大厦 从神经网络到 Hugging Face 在大理,听打雷 Git 纪元 凡所有相,皆是虚妄 马斯克的故事与模式 纳瓦尔的智慧 当魔法消失时 人生无论怎么度过都像是浪费 我们都是新穷人 代码、法律和自由软件 乾隆的性格 当下我们还需要启蒙吗? 云门胡饼赵州茶 上海周末骑行:从浦东到外白渡桥 如何选择图书译本? No.13: 周刊的周刊 读书日,推荐些童话和小说 学习邓小平的智慧 自建博客 Nginx 基本配置 给博客换了套新评论系统 我所理解的存在主义 心经说了什么 觉悟之道就是活在当下 巨人的笔记 从零到百亿美金之路 人生如逆旅,我亦是行人 和自己非暴力沟通 听斯蒂芬·金谈写作 行不尽,行不尽,一路青山 周刊第12期:第一次十字军东征 周刊第11期:玄奘之路 周刊第十期:敦煌 周刊第九期:卡片盒笔记法 爸爸是最聪明的 影响人类命运的是什么? 周刊第八期:如何应对公开错误 周刊第七期:如何学习 周刊第六期 周刊第五期 只买书:一个失败的微信小程序产品 改变世界的一次代码提交 如何成为一名黑客 通往开源之路 空山不见人 如何做好演讲 “人生在世,永远也不该演戏作假” 周刊第四期 大卫四岁读的书 宇宙就是一个蛋 周刊第三期 周刊第二期 周刊开刊 阅读开源代码小技巧 重学C语言 英国随记 变成神的动物 人类伟大的时刻 最著名的黑客 《巨婴国》读后 若为自由故 买房记 答案在风中飘 陪产记 自由的代价 谈一谈英语学习 读《霍乱时期的爱情》 简洁 嵌套的梦 四月莎士比亚 七律三首 从明天起,做一个Scrum Master 不能承受的生命之轻 我是丽莎呀 爱美丽、黑暗王子和豌豆公主 诗歌与烟台
Ruby 编程语言入门
胡涂说 · 2021-01-24 · via 胡涂说

Ruby is designed to make programmers happy. -- Matz (松本行弘)

松本行弘于1993年开始编写 Ruby 编程语言,并于 1995年发布。2006年 DHH 发布 Ruby on Rails 框架,Ruby 开始流行,并于 2006年被 TIOBE 选为年度编程语言。最近这些年因为云计算和移动互联网的兴起,Ruby 与同类语言相比显得不那么火。不过我倒是一直听喜爱 Ruby, 最近的项目又要用到 Ruby, 便整理下 Ruby 的一些知识教程。以下关于 Ruby 的语法介绍和示例主要来自《The Ruby Programming Languange》这本书1。(这本书是松本行弘本人所写,学习 Ruby 语言必看。)

语法

Ruby 是一款解释型、强类型、动态类型的面向对象编程语言。Ruby 语法优雅,目标是做到尽可能贴近英文语法。

1. Hello world

到 Ruby 的官网2上下载 Ruby 程序,推荐使用 Unix-like 操作系统,如 MacOS、Linux,而一般不建议用 Windows。推荐使用 rbenv 或 RVM 来安装,详细可参见网站指导。安装好 Ruby 后可执行 ruby 来执行 ruby 语言脚本,也可以输入 irb 打开 Ruby 交互式命令行工具(interactive ruby)开始使用。在 irb 上输入:

p 是 Ruby 的标准输出函数 puts 的简写。这里便可以看到 irb 返回 'hello, world!' 输出。

如果要打印5次 'hello, world!', 那只需要写:

是不是很有意思。

2. 类型

Ruby 中所有值都是对象(包括 nil 值),可以通过调用 class 方法来获知其类。Ruby 不像其他语言一样区分基本类型(primitive types) 和对象类型(object types),对于 Ruby 而言,所有类型都继承自 Object 类(根类为 BasicObject).

试着在 irb 上输入:

数字(Numeric)

Ruby 中包含五种 built-in 数字类型类: Numeric, Integer, Float, Fixnum 和 Bignum, 另外标准库中还提供了三种数字类型:Complex, BigDecimal, Rational. 除 Numeric 类外其他数字类型类都继承自 Numeric, 关系如下:

31 位以内的整数为 Fixnum, 超过位数为 Bignum, Bignum 没有位数限制。

对于大数 Ruby 提供了分段表示或科学计数法方便阅读,如:

  • 运算符

Ruby 支持基本的数学运算符(+, -, *, /),及取余(%), 求指数(**),等。

所有数字对象均为不可变值,因此 Ruby 中也没有自增和自减操作符(++, --)。

  • 浮点数精度问题

与 C 等语言的浮点数运算结果一样,上述表达式运算的结果为 false, 不过 Ruby 提供了一种解决方案,即标准库中提供的 BigDecimal 类,使用该类可以按实际值运算,但效率比浮点数慢。

文本(String)

Ruby 有多种文本的表达方式:

1. 简单文本以单引号('')包含, 除 '\ 字符外都不会转义。
2. 普通文本以双引号("")包含,可转义字符,且可以包含变量或表达式(内嵌 #{ expr })。

也可以用类似 C 语言的 sprintf 格式化输出表示:

3. 自定义分隔符表示

%q%Q 开头,紧接着以及一个符号开始,如 |/\!;: 等,而如果分隔符是以 {[(< 开始的,那么字符串认定则到以匹配到 }])> 为止。%q 对应单引号 ' 文本, %Q 对应双引号 " 文本,其中 %Q 可省略 Q, 简写为 %. 例:

4. HERE 文档

对于大段文本,Ruby 提供了一种表示方法:以 <<<<- 开头,紧接一个任意标志字符串(如下面例子中的 HERE),那么从此行后到第一个遇到该字符串匹配行之前的文本都是表示文本内容。

  • 在 Ruby 中,文本(字符串)值默认是可变值,这与其他语言是不同的。

数组(Array)

1. 定义

有两种定义数组的方式:

对于字符串数组,有还可以这样定义:

2. 数组类型是动态的,一个数组中可包含任意类型的数据

向数组中追加数据使用 push 方法,或者更简单的 <<:

3. 数组下标

范围(Range)

Range 表示一个区间,以 ..... 来表示,区别是后者不包含结束值。

哈希(Hash)

Hash 是以{}表示的键值对数据结构,有两种定义方式:

而如果键值以 symbol 来表示的话,可以简写成:

符号(Symbol)

符号(Symbol)可以理解为一种特殊的字符串对象,作为名称标签使用,用来表示方法等对象的名称,一般 hash 的键值会用符号来表示,比字符串更高效。符号和字符串可以互相转换:

true, false, nil

true 和 false 为两个布尔型的值,与其他语言理解有差别的是,除了 false 和 nil 外,其他值都为 true:

nil 表示空值。对于值判空操作可调用 nil? 方法:

3. 表达式

赋值

defined? 操作符

defined? 操作符可以判断变量、函数、符号等是否定义:如果右值定义,则返回一个字符串;否则为 nil.

4. 条件及循环

if 和 unless

或者更简洁的写法:

注意,上述下面的写法中 then 不可省略。

另外,如果表达式只有一句,if 一般放在语句后面,更符合英语语法习惯:

unless 含义与 if 相反,相当于 if not.

case

case 语句即 C 语言中的 switch/case:

if 语句类似, when 条件后的逻辑语句如果另起一行,可省略 then

while 和 until

if 语句类似,如果循环处理语言只有一行,可将 while 条件放在语句结尾:

或:

until 相当于 while not.

for/in

迭代器

虽然 Ruby 提供了 while/until/for 循环控制语句,但实际上在编程中使用不多。在 Ruby 编程中对循环处理逻辑使用更普遍的是迭代器(Iterator)的写法。如开头示例中的打印五次 'hello, world'。而一些 Enumerable 对象中提供的迭代器调用比使用 for 语句更简洁:

除 Enumerable 类的迭代器外,Numeric 类也提供了几种迭代器方法:

  • 写一个迭代器

yield 关键字来调用迭代器处理的 block ({}中的语句):

break, next, redo

  • break: 从循环或迭代器中跳出。
  • next: 从循环或迭代器中调到下一个循环处理。
  • redo: 重新从循环或迭代器开头执行。

4. 异常处理

Ruby 中也有 throwcatch 关键字,但这两个配对主要是用在多层循环语句中直接跳出,类似于 C 语言中的 goto. Ruby 的异常处理使用 raise/rescue/ensure, 相当于 Java 中的 try/catch/finally.

如果 begin 在方法开始处,则 begin 可省略。

5. 方法(Method)

一般语言中会区分函数(function)和方法(method),用于区分直接调用的函数和对象的方法。而 Ruby 是完全的面向对象,因此,所有的函数都是方法,如果没有定义在类或模块内部,那么会被作为 Object 的私有方法定义并调用。

定义

def 关键字定义:

方法中的 return 关键字可省略,除非提前条件退出的逻辑需加上 return.

调用方法时,可省略小括号(),如:

方法别名

参数

方法支持默认参数:

支持可变参数,参数作为数组使用:

如果将数组作为参数传入方法,需要在数组变量前加 *:

如果哈希值作为最后一个参数,可以省略调用的 {}(这在 Rails 中应用非常广泛):

但如果调用时加上{}, 需要同时带上 (), 否则会出错,因为 Ruby 会将 {} 当成 block 块:

block 块作为参数:

TODO...

名称约定

方法名后缀有些约定,方法名后跟 ? 一般表示返回 true/false, 跟 ! 表示该方法具有破坏性。这种后缀是一种约定而非强制。

= 后缀的方法将在赋值语句中调用,对应其他语言中的 setter 方法。

Proc, lambda

proc 和 lambda 都是闭包(closure); TODO...

6. 类

定义

类名需以大写字母开头:

实例化对象:

成员变量及成员方法

成员变量名以 @ 开头,类变量名以 @@ 开头。

类的构造函数名称为 initialize

上面的实现在 ruby 中有更简洁的语法可以自动生成 getter 和 setter 方法功能:

如果是只读成员变量仅提供 getter 方法的话可以使用 attr_reader 关键字:

运算符方法

对类实现运算符方法,如 +-*/, 需要注意的是由于一元-运算符(求负)与减法预算负是同一个字符,因此,Ruby 使用 -@ 来表示一元-运算符方法:

类方法

类方法定义与成员方法定义不同在方法名前加类名或 self 关键字:

如果有多个类方法定义,可将它们放一起,如下方式定义:

public, protected, private

方法默认为 public, protected, private 的方法需要显示声明:

继承

类的继承用符号 <,继承特性与其他面向对象语言类似,方法可被子类重写,重写方法如果需要调用父类方法,可使用 super 关键字来调用。

7. 模块(Module)

Ruby 的模块(Module) 类似于其他语言的命名空间,但又提供了 Mixin 功能供其他类导入方法,可以理解成实现了方法的接口。

模块不能被实例化,不能被继承。

用作命名空间(namespace)

用作 Mixin

前面提到的 Enumerable 对象的类其实就是 Mixin 了 Enumerable Module. 使用 include 关键字 mixin 模块,便可将该模块的所有方法导入进类中。一个模块也可以 mixin 其他模块。

8. 其他语法

元编程

Ruby 提供了丰富的反射接口,这使得 Ruby 元编程非常容易,Ruby on Rails 框架正是利用了这一特性,构建了一套 Rails 的 DSL.

类型

Ruby 提供了多种获取、比较类型的方法:

eval 方法执行字符串

方法

通过 send 调用,将方法名作为 symbol 或字符串传给对象调用:

define_methodmethod_missing 是元编程较为常用的两个方法,define_method 可以动态定义函数,而 method_missing 则是在对象调用时没有查到方法时调用的方法。

项目应用

Gem, Bundler

Ruby 的包称为ruby gem, 包管理工具也是 gem. 而对于包依赖管理则是 bundler 来进行管理,在项目目录生成一个 Gemfile 文件,执行 bundle install 来自动安装依赖包。Gemfile 文件是这个样子:

testing

Ruby 的默认单元测试框架是 Test::Unit, 也可以换成如 rspec 之类。

rubocop

由于 Ruby 提供了丰富的语法,导致项目开发时可能会出现风格迥异的情况,因此,一些大型项目会定义 Ruby 的编程风格(code style),比较知名的有 airbnb 的 Ruby Style Guide.3

而工具检查方面,robocop 静态检查工具可以很好的检查 Code Style 的符合情况,另外,rubocop 也可以检查代码中的其他一些问题。

设计哲学

1. 让程序员享受编程的乐趣

Matz 认为编程语言首先应该是给程序员服务的。因此在 Ruby 首先考虑的是提升程序员的效率,让程序员满意,而非一味从服务器运行效率等机器角度考虑设计。

人们特别是电脑工程师们,常常从机器着想。他们认为:“这样做,机器就能运行的更快;这样做,机器运行效率更高;这样做,机器就会怎样怎样怎样。”实际上,我们需要从人的角度考虑问题,人们怎样编写程序或者怎样使用机器上应用程序。我们是主人,他们是仆人。4

Ruby 继承了 Perl 的设计原则(TMTOWTDI: There's More Than One Way To Do It),提供了处理同样事务的多种方法。这与 Python 的只提供一种解决方法的设计思想(Zen of python: There should be one-- and preferably only one --obvious way to do it)恰恰相反。对于程序员而言,Ruby 更自由、更灵活,但也会导致多人项目的代码风格迥异,可读性不如 python 代码。

就我个人而言,Ruby 编程确实很有意思,一方面是 Ruby 可以用很少量的代码实现更多的功能,另一方面是能想到的功能基本上没有什么语法限制,都可以实现。

2. 最小惊讶原则(POLA: principle of least astonishment)

Matz 认为编程语言应该尽可能符合程序员的预期,也就是所谓的“最小惊讶原则”。有一个典型的例子,如果在 python 的终端交互界面上输入 exit, python 会提示让你加括号,可是既然编程语言都判断出用户想退出了,为什么还需要让用户再次输入精确的命令呢?相反的,在 irb 上输入 exit, quit 都可以实现用户的预期 —— 退出交互终端。

不过 Ruby 里也有让人“惊讶”的地方,最为诟病的一点是关于布尔判断,在 Ruby 里面,除了 false 和 nil 被判断为 false 外,其他都为 true, 包括 0, [], 这与很多语言的布尔判断约定是不一样的。

3. 一切皆对象

Ruby 是存粹的面向对象语言,上述语法也说明了这一点。

当然 Ruby 也比较有争议性,喜欢的人很喜欢,不喜欢的人理由也有千千条。但对于喜欢 Ruby 的人来说,Ruby 的缺点都不算缺点,正如 Ruby on Rails 的创始人 dhh 最近在 Twitter 上说: "Ruby was fast enough in 2003 to build a business like Basecamp with no impediments." 尽管2003年的 Ruby 是被吐槽出奇慢的 1.8 版本。


Footnotes

  1. The Ruby Programming Languange

  2. Ruby official

  3. Airbnb's Ruby Style Guide

  4. The Philosophy of Ruby - A Conversation with Yukihiro Matsumoto, Part I