Ruby 块(产量)

Ruby Blocks (Yield)

我才刚刚开始学习 Ruby,我在 Bloc 的课程已经很顺利了,但现在我被困在一个关于 yield 和 blocks 的练习中(我发现这是学习时迄今为止最难掌握的概念 ruby)。

以下是纯格式文本所需的规范:


以下是需要满足的 RSpecs:

describe "new_map" do
  it "should not call map or map!" do
    a = [1, 2, 3]
    a.stub(:map) { '' }
    a.stub(:map!) { '' }

    expect( new_map(a) { |i| i + 1 } ).to eq([2, 3, 4])
  end

  it "should map any object" do
    a = [1, "two", :three]
    expect( new_map(a) { |i| i.class } ).to eq([Fixnum, String, Symbol])
  end
end

这是他们给我的原始 def 方法:

def new_map(array)
  new_array = []
  array.each do |item|
    # invoke the block, and add its return value to the new array
  end
end

然后这是我当前的代码(更新):

def new_map(a)
  new_array = []
  a.each do |item|
    # invoke the block, and add its return value to the new array.
    yield(item, new_array)
  end
end

a = [2, 3, 4]

new_map(a) do |i, e|
  e << i
end

最后,当我提交我刚刚列出的当前代码时,我收到以下错误(已更新):

new_map should not call map or map! (INCOMPLETE)

    expected: [2, 3, 4]
     got: [1, 2, 3]

(compared using ==)
exercise_spec.rb:9:in `block (2 levels) in <top (required)>'

new_map should map any object (INCOMPLETE)

expected: [Fixnum, String, Symbol]
     got: [1, "two", :three]

(compared using ==)

exercise_spec.rb:14:in `block (2 levels) in <top (required)>'

new_array 是在定义 new_map 中创建的,与调用 new_map 时编写的块不同 "lexical scope"。基本上,new_map 方法中的代码可以看到 new_array,但您的块中的代码不能。解决此问题的一种方法可能是查看 Enumerable 方法 injecteach_with_object 可以代替 new_map 方法中的 each

您没有意识到 yield 可以 return 一个值。块中最后执行的语句是 returned 值。

因此您可以从每个 yield 调用中获取结果并将其添加到结果数组中。

然后,将结果数组作为您的 new_map 方法的 return 值。

def new_map(a)
  new_array = []
  a.each do |item|
    # invoke the block, and add its return value to the new array.
    new_array << yield(item)
  end
  new_array
end

试试这个:

def new_map(a)
  new_array = []
  a.each do |item|
    # # invoke the block, and add its return value to the new array.
    puts yield(item) # just experimenting
  end
end

new_map(a) { |i| i + 1 }

这个yield 东西只是从数组中取出每个元素,并在块中运行它。这个实验代码只是打印结果;这些应该收集在一个数组中。不难:

def new_map(a)
  new_array = []
  a.each do |item|
    new_array = []
    # invoke the block, and add its return value to the new array.
    new_array << yield(item)
  end
end

这不会通过所有测试,但最后一步应该是可行的。