这是我根据TeamTreeHouse上Ruby轨道上的Ruby块的视频课程创建的代码,这是代码及其输出。
我的代码:
def get_name(prompt, &block)
print prompt + ": "
name = gets.chomp
print "age: "
age = gets.chomp
#block.call(nam,ag)
yield name, age
yield age
name
end
my_name = get_name("enter your name") do |name, age|
puts "That's a cool name, #{name}, #{age}"
end
my_name2 = get_name("enter your age") do |age|
puts "That's a cool age, #{age}"
end
puts "my_name: #{my_name} #{my_name2}"
我的输出:
treehouse:~/workspace$ ruby calling_blocks.rb
enter your name: ahmed
age: 25
That's a cool name, ahmed, 25
That's a cool name, 25,
enter your age: 25
age: 25
That's a cool age, 25
That's a cool age, 25
my_name: ahmed 25
该代码的问题在于,在跟踪它时,我发现输出无关紧要,我认为必须发生以下情况:
1-第一个get_name块发送了一个带有问题"输入您的名字"的提示,然后该方法get_name首先打印短语"输入您的名字",该短语作为称为提示的参数,然后该方法将名称作为输入并将年龄作为输入
2-第一个收益"yield名称,年龄"发送回第一个get_name块的名称和年龄,通过|name,age|在块中接收,然后它们都显示在
puts "That's a cool name, #{name}, #{age}"
作为这个
That's a cool name, ahmed, 25
3-第二个收益"yield age"这次只发送回第一个get_name块的age,它通过|name,age|在块中接收,这次由于我们只发送回块一个参数,而块有两个参数,这次块上的name参数接收到来自"yield name"的age参数, 虽然块上的 age 参数没有收到任何内容,所以在块中,#{name} 只显示值,而 #{age} 不显示任何值
puts "That's a cool name, #{name}, #{age}"
作为这个
That's a cool name, 25,
我的追踪是真的吗? 因为如果这是真的,为什么在第二个get_name块中,这是
my_name2 = get_name("enter your age") do |age|
puts "That's a cool age, #{age}"
end
输出为:
That's a cool age, 25
That's a cool age, 25
而不是:
That's a cool age, ahmed
That's a cool age, 25
另一个问题: 在
puts "my_name: #{my_name} #{my_name2}"
为什么 #{my_name2} 的值 = 25,而不是 = 艾哈迈德,知道 get_name 方法的最后一行,我返回 name,而不是年龄?
这个问题的简短版本: 请为我跟踪我的代码,告诉我到底发生了什么?
1)get_name
方法产生name
并adge
块。在块内分配了这些变量:name="ahmed", age=25
。输出为That's a cool name, ahmed, 25
2)get_name
方法将adge
成块。在块内分配了这些变量:name=25, adge=nil
。(这是一个Proc,而不是lambda,因此它将nil
设置为未获得的变量)。输出为That's a cool name, 25,
。看到25
后的逗号了吗?它实际上也打印nil
,但nil.to_s
是空字符串。
3) my_name = "艾哈迈德" - 变量被分配
4)由于您的新提示是"输入您的年龄"并且您输入25,因此get_name
方法中将其分配给name
变量。然后,再次输入 25,该值也会分配给age
。
5)get_name
产生两个值(name
和age
现在25
和25
)只接受第一个的块。然后get_name
生成一个age
该块的值。
6)my_name_2=get_name#name=25
你只能使用显式参数形式 (&block
) 或yield
,但不能两者兼而有之。现在你的&block
论点被完全忽略了。
如果使用&block
,则可以将yield(
替换为block.call(
。
无论哪种情况,调用堆栈都不是超级复杂。在你调用yield(
或block.call(
的地方,它进入给定的块(你调用puts
),然后转到下一行。
另一个需要理解的重要事情是,块不会验证传递给它们的参数数量。有人在StackOverflow评论中给出了一条建议(不知道源链接),我觉得记住它很有帮助。块的行为类似于 proc——它们不验证参数的数量,你可以记住这一点,因为单词是相似的。方法的行为类似于 lamdas——它们确实验证了参数的数量。
因此,当您连续两次调用yield
时,这是使用不同的参数多次调用同一块。当您使用不同的do
部分调用函数两次时,您将提供两个不同的块。