深入理解 Ruby 中的代码块:The Odin Project 高级 Ruby 教程

深入理解 Ruby 中的代码块:The Odin Project 高级 Ruby 教程

curriculum TheOdinProject/curriculum: The Odin Project 是一个免费的在线编程学习平台,这个仓库是其课程大纲和教材资源库,涵盖了Web开发相关的多种技术栈,如HTML、CSS、JavaScript以及Ruby on Rails等。 curriculum 项目地址: https://gitcode.com/gh_mirrors/cu/curriculum

前言

在 Ruby 编程语言中,代码块(Blocks)是最基础也是最强大的特性之一。本文基于 The Odin Project 高级 Ruby 课程中的相关内容,将深入探讨 Ruby 代码块的各个方面,包括 yield 关键字、Proc 对象、Lambda 表达式等高级用法。

代码块基础回顾

在开始深入之前,让我们先快速回顾一下代码块的基础知识:

# 单行代码块
[1,2,3].each { |num| puts num }

# 多行代码块
[1,2,3].each do |num|
  puts num
end

Ruby 约定俗成的规范是:

  • 单行代码块使用大括号 {}
  • 多行代码块使用 do..end
  • 可以通过管道符 |arg1, arg2| 向代码块传递参数

yield 关键字详解

yield 是 Ruby 中一个强大的关键字,它允许方法将执行权暂时交给伴随的代码块。

基本用法

def logger
  yield
end

logger { puts '来自代码块的问候' }
#=> 来自代码块的问候

多次调用 yield

一个方法中可以多次调用 yield

def double_vision
  yield
  yield
end

double_vision { puts "我举着几根手指?" }
#=> 我举着几根手指?
#=> 我举着几根手指?

向代码块传递参数

可以通过 yield 向代码块传递参数:

def love_language
  yield('Ruby')
  yield('Rails')
end

love_language { |lang| puts "我爱#{lang}" }
#=> 我爱Ruby
#=> 我爱Rails

实际应用示例

假设我们正在开发一个银行应用,需要打印交易记录:

@transactions = [10, -15, 25, 30, -24, -70, 999]

def transaction_statement
  @transactions.each do |transaction|
    yield transaction
  end
end

transaction_statement do |transaction|
  p "%0.2f" % transaction
end
#=> ["10.00", "-15.00", "25.00", "30.00", "-24.00", "-70.00", "999.00"]

这种设计允许不同的银行使用相同的交易处理方法,但自定义不同的显示格式。

代码块控制

检查代码块是否存在

当方法需要代码块但调用者没有提供时,会抛出错误。可以使用 block_given? 方法进行检查:

def maybe_block
  if block_given?
    puts "有代码块"
  end
  puts "无论如何都会执行"
end

maybe_block
#=> 无论如何都会执行

maybe_block {} # {} 是一个空代码块
#=> 有代码块
#=> 无论如何都会执行

Lambda 表达式

Lambda 是一种将代码块保存为变量的方式,特别适用于需要在多个地方重用相同代码块的情况。

创建 Lambda

有两种创建 Lambda 的方式:

# 使用 lambda 关键字
my_lambda = lambda { puts "我的lambda" }

# 使用 "stabby lambda" 语法
my_other_lambda = -> { puts "另一边的问候" }

调用 Lambda

my_lambda = -> { puts "击掌" }
my_lambda.call
#=> 击掌

带参数的 Lambda

my_name = ->(name) { puts "你好 #{name}" }
my_age = lambda { |age| puts "我今年 #{age} 岁" }

my_name.call("小明")
#=> 你好 小明
my_age.call(25)
#=> 我今年 25 岁

Proc 对象

Proc 是另一种保存代码块的方式,与 Lambda 类似但有重要区别。

创建 Proc

# 使用 Proc.new
a_proc = Proc.new { puts "这是一个proc" }

# 使用 proc 方法
a_proc = proc { puts "这也是一个proc" }

a_proc.call
#=> 这是一个proc

带参数的 Proc

a_proc = Proc.new { |name, age| puts "姓名: #{name} --- 年龄: #{age}" }
a_proc.call("张三", 30)
#=> 姓名: 张三 --- 年龄: 30

Proc 与 Lambda 的区别

参数处理

Proc 对参数数量不敏感,而 Lambda 会严格检查参数数量:

# Proc 示例
a_proc = Proc.new { |a, b| puts "a: #{a} --- b: #{b}" }
a_proc.call("苹果")
#=> a: 苹果 --- b:

# Lambda 示例
a_lambda = lambda { |a, b| puts "a: #{a} --- b: #{b}" }
a_lambda.call("苹果")
#=> 错误:参数数量错误 (给定 1,需要 2) (ArgumentError)

返回行为

Lambda 中的 return 只从 Lambda 中返回,而 Proc 中的 return 会从定义 Proc 的上下文中返回:

# Lambda 返回
a_lambda = -> { return 1 }
a_lambda.call
#=> 1

# Proc 返回
def test_method
  a_proc = Proc.new { return }
  puts "这行会被打印"
  a_proc.call
  puts "这行永远不会执行"
end

test_method
#=> 这行会被打印

捕获代码块

Ruby 允许我们在方法定义中使用 & 来捕获代码块:

def cool_method(&my_block)
  my_block.call
end

cool_method { puts "酷" }
#=> 酷

& 操作符实际上会调用 #to_proc 方法,将代码块转换为 Proc 对象。

总结

Ruby 的代码块机制提供了极大的灵活性,通过 yield、Proc 和 Lambda,我们可以实现各种高级编程模式。理解它们之间的区别和适用场景,对于编写优雅、高效的 Ruby 代码至关重要。

关键点回顾:

  • yield 允许方法将控制权交给代码块
  • block_given? 可以检查是否提供了代码块
  • Lambda 是严格版本的 Proc,会检查参数数量
  • Proc 的 return 行为与 Lambda 不同
  • 可以使用 & 捕获代码块并转换为 Proc 对象

掌握这些概念将大大提升你的 Ruby 编程能力,让你能够编写更加灵活和强大的代码。

curriculum TheOdinProject/curriculum: The Odin Project 是一个免费的在线编程学习平台,这个仓库是其课程大纲和教材资源库,涵盖了Web开发相关的多种技术栈,如HTML、CSS、JavaScript以及Ruby on Rails等。 curriculum 项目地址: https://gitcode.com/gh_mirrors/cu/curriculum

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜月锴Elise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值