在Ruby on Rails上解释Iterator语法

我开始学习Ruby on Rails并发现自己对语法感到困惑,所以我不得不阅读一些Ruby语法。 我从http://www.cs.auckland.ac.nz/references/ruby/doc_bundle/Manual/man-1.4/syntax.html学习了语法:

method_call do [`|' expr...`|'] expr...end 

他们称之为迭代器。 我理解一个迭代器运行循环,但我不明白我应该如何阅读这个或者在这个语法中发生了什么。 我一直在RoR的截屏video中看到它并且这些词语有意义,但我实际上不知道发生了什么。 谁有人向我解释这个?

编辑:示例

 respond_to do |format| format.json format.xml { render :xml => @posts } end 

方法可以采用称为“块”的构造。 这些是传递给方法的匿名方法。

另一种语法是:

 method_call { |var| do_something(var) } 

基本上,您是说对于迭代中的每个项目,将其命名为“var”并对该项执行某些操作。 该方法只是调用您传入的块,因为它会“生成”项目。

这有帮助吗?

编辑:在你的例子中,他们以一种有趣的方式使用迭代器模式…可能只将一个format对象传递到你的块中,这样你就可以告诉它要处理哪些格式,以及当你看到它时要做什么。

换句话说,他们正在使用该模式创建各种DSL,以便您配置响应的内容。

在迭代器的情况下,将它们想象成Java中的接口:您可以在Ruby中执行for循环,但是您可能想要迭代的所有对象(应该)实现需要块的“each”方法(即一个闭包,一个匿名函数)。

块在Ruby中被遍地使用。 想象一下你有这个数组:

 [1, 2, 3, 4, 5, 6].each do |i| puts i.to_s end 

在这里,您正在创建数组,然后您在其上调用’each’方法。 你把块传递给它。 您可以将其分开,如下所示:

 arr = [1, 2, 3, 4, 5, 6] string_printer = lambda do |i| puts i.to_s end arr.each(&string_printer) 

这种接口在其他方面实现:Hash集合允许您迭代键值对:

 {:name => "Tom", :gender => :male}.each do |key, value| puts key end 

do..end可以替换为大括号,如下所示:

 [1, 2, 3, 4, 5, 6].each {|i| puts i.to_s } 

由于Ruby使用的函数编程,这种迭代成为可能:如果您正在创建需要迭代某些东西的类,您还可以实现每个方法。 考虑:

 class AddressBook attr_accessor :addresses def each(&block) @addresses.each {|i| yield i } end end 

各种类通过这种块模式实现了有趣的function:例如,查看String的each_line和each_byte方法。

 method_call do [`|' expr...`|'] expr...end 

不仅限于迭代函数。

在ruby中,任何方法都可以将块作为参数。 然后可以通过该方法调用该块。 在迭代器的情况下,该方法看起来像这样:

 def iter for i in [:x,:y,:z] yield i end end 

如果你用一个块调用iter ,它将循环遍历[:x, :y, :z]并将它们中的每一个放到块中,然后可以执行任何操作。 例如打印出来:

 iter { |z| puts z } 

您还可以使用它来隐藏初始化和清理步骤,例如打开和关闭文件。 例如File.open 。 File.open,如果它是在纯ruby中实现的(它在C中表示性能)会做这样的事情。

 def File.open filename, opts f = File.new filename, opts yield f f.close end 

这就是你可以使用的原因

 File.open 'foobar', 'w' do |f| f.write 'awesome' end 

respond_to是类似的。 它的工作原理如下:(查看这里的实际实现)

  def respond_to responder = Responder.new(self) block.call(responder) responder.respond end 

它创建一个响应器对象,其中包含html方法,它们会将块传递给您。 事实certificate这非常方便,因为它可以让你做以下事情:

 def action @foo = Foo.new params[:foo] respond_to do |format| if @foo.save format.html { redirect_to foo_path @foo } format.xml { render :xml => @foo.to_xml } else flash[:error] = "Foo could not be saved!" format.html { render :new } format.xml { render :xml => {:errors => @foo.errors }.to_xml} end end end 

看看我如何改变依赖于块内保存的行为? 没有它,这样做会更烦人。

  do ||  end 

这将创建一个临时匿名函数,该函数将项接受到临时变量中,然后让事物对该项进行操作。 匿名函数被传递给指定的原始 ,以对该函数产生的项进行操作。

你看到的是一段代码,当你第一次看到它时,语法有点尴尬。

所以,基本上,对于迭代器,你有一个可以重复的“东西”,它会收到一个块来知道该怎么做。

例如, Range类有一个名为“each”的方法,它接收要在该范围内的每个元素上执行的代码块。

假设您要打印它:

 range = 1..10 #range literal range.each {|i| puts i } 

代码: {|i| puts i} {|i| puts i}是一个块,它说明当这个范围迭代每个元素时该怎么做。 替代语法是您发布的语法:

  range.each do |i| puts i end 

这些块与迭代器一起使用,但它们不限于“迭代”代码,您可以在其他场景中使用它们,例如:

 class Person def initialize( with_name ) @name = with_name end # executes a block def greet yield @name #passes private attribute name to the block end end p = Person.new "Oscar" p.greet { |n| puts "Name length = #{n.length}" puts "Hello, #{n}" } 

打印:

 Name length = 5 Hello, Oscar 

因此,使用块而不是使用具有固定行为的greet方法,让开发人员指定要做什么,这对迭代器非常有帮助,但是您只是见证了不是唯一的地方。 在您的情况下,该块允许您指定在respond_to方法中执行的操作。

你正在阅读的文件很古老 – 实际上是史前的。 如果网页可能会聚集灰尘,那么会有一层厚厚的网页。

在ruby-lang网站上试用参考资料。 此外, Programming Ruby (pickaxe)书籍是必不可少的参考书。

我认为你可以称之为迭代器,因为通常会多次调用块函数。 如:

 5.times do |i| puts "#{i} " end 

“在幕后”,执行以下步骤:

  • 调用对象实例5的方法times ,传递代码puts "#{i} "放入Proc对象实例中。
  • times方法中,此代码在循环内部调用,将当前索引作为参数传递。 这就是times样子( 实际上是在C中 ):

 class Fixnum def times_2(&block) # Specifying &block as a parameter is optional return self unless block_given? i = 0 while(i < self) do yield i # Here the proc instance "block" is called i += 1 end return self end end 

请注意,范围(即局部变量等)被复制到块函数中:

 x = ' ' 5.times do { |i| puts "#{i}" + x }