什么```变量在`times {| i | ......}`代表什么?

时间:2016-02-27 16:51:56

标签: ruby

我正在尝试阅读代码以便理解。基本上这个代码应该做的是取一个名为new_str的字符串(其数字字符总是5的倍数)并将其字符放入另一个名为new_str_2的字符串中,以5为一组,后跟空格。例如,如果new_str"onetwothre",则new_str_2"onetw other"。但我的问题是变量i.times阻止中做了什么?

new_str = "thisisyetanotherstringwithoutspaces"
new_str_2 = ""
(new_str.size / 5).times { |i| new_str_2 << new_str[i * 5, 5] << " " }
new_str_2 #=> "thisi syeta nothe rstri ngwit houts paces "

5 个答案:

答案 0 :(得分:1)

如果有一个像变量一样给出的块,那么它将从0到(new_str.size / 5) - 1

计数

Doc

答案 1 :(得分:1)

(new_str.size / 5).times { |i| new_str_2 << new_str[i * 5, 5] << " " }

是一个枚举器,后跟一个块。枚举器是类Enumerator的一个实例,是

enum = (new_str.size / 5).times
  #=> #<Enumerator: 7:times>

我们可以通过将它转换为数组来检查这个枚举器的元素:

enum.to_a
  #=> [0, 1, 2, 3, 4, 5, 6]

当Ruby看到一个枚举器后跟一个块时,她将方法Enumerator#each发送给枚举器:

enum.each { |i| new_str_2 << new_str[i * 5, 5] << " " }
  #=> 7
new_str_2
  #=> "thisi syeta nothe rstri ngwit houts paces " 

eachenum的每个元素传递给块,将块变量设置为等于其值。我们可以使用方法Enumerator@next来查看如何完成此操作:

i = enum.next #=> 0
i = enum.next #=> 1
i = enum.next #=> 2
...

i的每个值执行块计算。

现在让我们考虑第二个例子:

[[1,2], [3,4]].map { |a| a[0] + a[1] }
  #=> [3,7]
enum = [[1,2], [3,4]].map
  #=> #<Enumerator: [[1, 2], [3, 4]]:map> 
enum.to_a
  #=> [[1, 2], [3, 4]] 
enum.each { |a| a[0] + a[1] }
  #=> [3, 7] 
a = enum.next
  #=> [1, 2] 
a[0] + a[1] 
  #=> 3 
a = enum.next
  #=> [3, 4] 
a[0] + a[1] 
  #=> 7

通常你会看到这个写的

[[1,2], [3,4]].map { |a,b| a + b }
  #=> [3,7]

可以说更清楚。步骤与以前一样,除了为块变量赋值时使用并行赋值(又名多重赋值):

enum = [[1,2], [3,4]].map
  #=> #<Enumerator: [[1, 2], [3, 4]]:map> 
a,b = enum.next
  #=> [1, 2]
a #=> 1 
b #=> 2 
a + b
  #=> 3 
a,b = enum.next
  #=> [3, 4] 
a #=> 3 
b #=> 4 
a + b
  #=> 7 

在许多情况下,可以使用对块变量的值的并行分配。还有一个使用方法Enumerable#each_with_object

[[1,2], [3,4]].each_with_object({}) { |(a,b),h| h[a] = b }
  #=> {1=>2, 3=>4} 

enum = [[1,2], [3,4]].each_with_object({})
  #=> #<Enumerator: [[1, 2], [3, 4]]:each_with_object({})> 
enum.to_a
  #=> [[[1, 2], {}], [[3, 4], {}]] 

(a,b),h = enum.next
  #=> [[1, 2], {}] 
a #=> 1 
b #=> 2 
h #=> {} 
h[a] = b
  #=> 2 
h #=> {1=>2} 

(a,b),h = enum.next
  #=> [[3, 4], {1=>2}] 
a #=> 3 
b #=> 4 
h #=> {1=>2} 
h[a] = b
  #=> 4 
h #=> {1=>2, 3=>4} 

请注意,Enumerator#each_objectEnumerator的{​​{1}}对应方)可用于解决手头的问题:

Enumerable#each_with_object

答案 2 :(得分:0)

i是从new_str_2 << new_str[i * 5, 5] << " "获得代码(new_str.size / 5).times的内容。

答案 3 :(得分:0)

(new_str.size / 5).times { |i| new_str_2 << new_str[i * 5, 5] << " " }

为简化操作,new_str.size / 5评估为7。所以你的表达式与:

相同
7.times { |i| new_str_2 << new_str[i * 5, 5] << " " }

i=0i=6开始,您的代码块 7次。首先,我们将i=0传递给块。然后执行以下步骤:

  1. { |i| new_str_2 << new_str[i * 5, 5] << " " }

  2. { |i=0| new_str_2 << new_str[0 * 5, 5] << " " }

  3. { |i=0| new_str_2 << new_str[0, 5] << " " }

  4. { |i=0| new_str_2 << "thisi " }

  5. 然后times迭代器对i=1执行相同操作,依此类推i=6

答案 4 :(得分:0)

在Ruby中,块声明中||内声明的变量是“输入”参数。

鉴于,您有一个名为foo的函数可以使用一个块,您可以按如下方式使用它:

foo(method, arguments) do
  do something: funny
end

然后该块将在 foo方法内执行,在方法想要执行它的位置;这样代码就可以轻松改变方法的行为。

在某些情况下,块可能会将一些参数传递给您。您可以在||块中声明它们,一般来说,如果您不想使用它们,则可以声明它们。语法如下:

foo(method, arguments) do |first, second|
  my_method(first)
  puts second
end

因此,在times方法的情况下,它在循环中从times方法内部传递参数。它的内部定义可能类似于

def times count
  i = 0
  while i < count
    yield(i)
    i+=1
  end
end

会导致您的块被多次调用,每次都以i为参数。