我试图了解grep在这个例子中是如何工作的。代码有效,但我不是100%确定事件发生的顺序,或者我是否正确理解了何时何地返回的内容。
cars = [:Ford, :Toyota, :Audi, :Honda]
ucased_cars = cars.collect do |c|
c.to_s
end
.grep(/^Ford/) do |car|
puts car.upcase
car.upcase
end
puts "ucased:" + ucased_cars.to_s
我认为发生的事情是:
就第4步而言,以下哪项最能说明grep的工作原理:
[A] grep查找与模式匹配的所有字符串。 grep在这个匹配数组上调用块。 grep将块的结果返回给调用函数。
[B] grep找到匹配模式的第一个字符串。 grep在这场比赛中调用该块。这个区块的返回值暂时堆积在某个地方。 grep搜索数组的下一个元素。如果匹配,grep会在此匹配上调用该块。 grep将此块的返回值添加到返回值的临时“存储”中。 grep查看下一个数组元素,直到找不到更多匹配项。然后grep将堆积的返回值传递回调用函数。
我的结论:
[A]似乎更有意义。
[B]似乎有很多不必要的捏造,似乎没有效率或可能。
答案 0 :(得分:12)
首先,here's the documentation for grep
让我清理你的代码并逐一解释
# 1
cars = [:Ford, :Toyota, :Audi, :Honda]
# 2
ucased_cars = cars.collect do |c|
c.to_s
end.grep(/^Ford/) do |car| # 3
puts car.upcase # 4
car.upcase # 5
end
# 6
# 7
puts "ucased:" + ucased_cars.to_s
声明符号数组
使用collect将符号转换为字符串。得到["Ford", "Toyota", "Audi", "Honda"]
将此数组字符串输入grep。与正则表达式/^Ford/
匹配的任何项目都将被提供给块
该块打印出已获取的上传字符串
该块返回upcased字符串,grep然后作为“匹配值”
来自grep的返回值(这是所有“匹配值”的数组)被分配给ucased_cars
,它是["FORD"]
,因为那是唯一与之匹配的东西正则表达式。
然后打印出来。在数组上执行to_s
只会打印所有阻塞的元素。这不是很有用,最好打印ucased_cars.inspect
回答关于grep如何在幕后工作的问题......
上面的文档页面显示了grep本身的C源代码。它基本上是这样做的:
rb_iterate
遍历源代码中的每个元素,并传入一些特定于grep的代码。rb_iterate
也被collect
,each_with_index
和其他一些东西使用。 由于我们知道collect / each / etc是如何工作的,我们不需要在源代码中进行任何更多的探索,我们有答案,而且它是你的[B]。
为了更详细地解释,它是这样做的:
至于你对“A似乎更有意义”的评论 - 我不同意。
这个想法是该块使用每个元素执行某些操作。如果它首先扫描了源,然后将匹配数组传递给块,那么你的块就必须自己调用each
,这很麻烦。
其次,效率会降低。例如,如果您的块调用return
或引发错误,会发生什么?在它的当前版本中,您可以避免扫描其余的源。如果它已经预先扫描了整个源列表,那么你就浪费了所有这些努力。