ruby 从块中返回值而不从方法中返回

368yc8dk  于 2023-05-22  发布在  Ruby
关注(0)|答案(3)|浏览(181)

我有一个类Test

class Test 
  attr_accessor :data
  def initialize
    @data = [0, 1, 2, 3]
  end
  def map
    @data.map!{|i| i = yield i }
  end
end

我试着这样使用它:

a = Test.new

a.map{|i|
  if(i==2)
    i+=1
    break i  #<--- -This line is the focus
  else
    1
  end
}

puts a.data

我期望的输出是[1, 1, 3, 3]。结果是[1, 1, 2, 3]map中的块的最后一次迭代没有返回修改后的i
break i替换为next i。这正如我预期的那样执行,并产生输出[1, 1, 3, 1]
如何修改这段代码(或者,最好是我在第二个代码片段中指出的那一行),以便得到输出[1, 1, 3, 3]?换句话说,我怎样才能完成代码块,但将最后一个值传递回map?有没有一种简洁易读的方法来做到这一点(除了,比如说,切换一个布尔标志break_now)?

r9f1avp5

r9f1avp51#

我假设你问的是如何离开一个块并利用最后计算的值,而不是如何计算一组特定的数字;对于后者,可能有一个聪明的俏皮话。
不如这样:

class Test
  attr_accessor :data

  def initialize
    @data = [0, 1, 2, 3]
  end

  def modify
    @data.map! {|i| yield i }
  end
end

a = Test.new
a.modify do |i|
  break i if @done
  @done = i == 2
  @done ? (i + 1) : 1
end

puts a.data

另外一个想法-#map是Ruby中一个重要的方法,有一个特定的接口。在您的示例中,您修改了Test中的字段,从而违反了接口。因此,我使用了#modify这个名字。

afdcj2ne

afdcj2ne2#

一般来说,您可以通过修改产生的值来避免这种情况。例如,如果你的数组由String而不是Fixnums组成:

class Test
  attr_accessor :data

  def initialize
    @data = %w{a b c d}
  end

  def map
    @data.map! { |i| yield i }
  end
end

a = Test.new
a.map do |i|
  if i == 'c'
    i.next!
    break
  else
    'b'
  end
end

p a.data   #=> ["b", "b", "d", "d"]

您的示例的问题是this
Fixnum对象具有立即值。这意味着当它们作为参数赋值或传递时,传递的是实际的对象,而不是对该对象的引用。赋值不会为Fixnum对象设置别名。对于任何给定的整数值,实际上只有一个Fixnum对象示例…
固定数不能就地改变,所以下面代码块中的表达式i += 1不会影响上面代码块中i的值。这就是为什么在您的示例中得到2,而在我的示例中得到d

t2a7ltrp

t2a7ltrp3#

你必须这样做:

a.map{ |i| (i % 2 == 0) ? i + 1 : i }

当你使用map函数时,你不会改变'a'变量,如果你想改变'a'变量,请这样做:

a.map!{ |i| (i % 2 == 0) ? i + 1 : i }

'i'的新值是块返回的值,所以不要这样做:

a.map{|i| i = 1 }

因为如果你这样做:

a.map{|i| i = 1; 5 }

结果将是:

[5, 5, 5, 5]

相关问题