任何人都可以告诉我这段代码吗?

时间:2013-05-19 16:18:28

标签: ruby

我很容易对迭代感到困惑 - 任何人都可以告诉我这段代码的确切内容吗? 朋友和家人都是哈希,语言是Ruby。

friends.each { |x| puts "#{x}" } 
family.each { |x, y| puts "#{x}: #{y}" }

2 个答案:

答案 0 :(得分:4)

friends.each { |x| puts "#{x}" } 
family.each { |x, y| puts "#{x}: #{y}" }

第一个基本上相当于:

x = [friends.keys[0], friends.values[0]]
puts "#{x}"
x = [friends.keys[1], friends.values[1]]
puts "#{x}"
x = [friends.keys[2], friends.values[2]]
puts "#{x}"
# ...
x = [friends.keys[n], friends.values[n]]
puts "#{x}"

第二个:

x = family.keys[0]
y = family.values[0]
puts "#{x}: #{y}"
x = family.keys[1]
y = family.values[1]
puts "#{x}: #{y}"
x = family.keys[2]
y = family.values[2]
puts "#{x}: #{y}"
# ...
x = family.keys[n]
y = family.values[n]
puts "#{x}: #{y}"

在方法之后,只要有{ |...| ... }do |...|; ...; end之类的内容,就会创建所谓的块。该块传递给方法,该方法可以yield到块的参数。 Array#each将使用每个元素调用块; Hash#each将通过[key, value]

当然,你可以做一些完全不同的事情,如下:

def test
  yield('oh my')
  yield('i really')
  yield('like blocks')
end
test { |a| puts a }

哪个输出

oh my
i really
like blocks

如果yield数组为一个数组,则可以将其分配给多个或单个参数。

def test
  yield(['oh', 'my'])
  yield(['i', 'really'])
  yield(['like', 'blocks'])
end
test { |a, b| puts "#{a}-#{b}" }

哪个输出

oh-my
i-really
like-blocks

或者,如果您只接受块中的单个参数,它将作为数组传递

test { |a| puts a.inspect }

输出

["oh", "my"]
["i", "really"]
["like", "blocks"]

所以,说Array#each不存在,你想自己创建它。你可以做点什么

class Array
  def each
    i = 0
    while i < length_of_underlying_array
      next_element = get_element(i)
      yield(next_element)
    end
  end
end

或者,Hash#each

class Hash
  def each
    i = 0
    while i < length_of_underlying_hash
      next_key = keys[i]
      next_value = values[i]
      yield([next_key, next_value])
    end
  end
end

另一个一般提示,因为Ruby是开源的,你可以准确地看到在C中实现Array#eachHash#each的方式,它通常与上面的普通Ruby代码相匹配。

答案 1 :(得分:3)

  • 调用{a: => :b, :c => :d}时,哈希值[[:a, :b], [:c, :d]]会转换为数组each
  • 如果each上的阻截获取一个变量x,则会传递其中的每个元素,第一次迭代为[:a, :b],下一次为[:c, :d]
  • 如果each上的阻止了两个变量xy,那么像[:a, :b]这样的每个元素都会与变量匹配。对于第一次迭代,x变为:ay变为:b