我有一个班级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
)?
答案 0 :(得分:1)
我假设你问的是如何留下一个块并使用最后计算的值,而不是如何计算一组特定的数字;对于后者,可能有一个聪明的单行。
这样的事情怎么样:
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
。
答案 1 :(得分:0)
一般情况下,您可以通过修改现有的屈服值来避免这种情况。例如,如果您的数组由字符串而不是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对象实例...
Fixnums不能就地更改,因此下部块中的表达式i += 1
不会影响上部块中i
的值。这就是您在示例中获得2
但在我的示例中获得d
的原因。
答案 2 :(得分:-1)
你必须这样做:
a.map{ |i| (i % 2 == 0) ? i + 1 : i }
使用地图功能时,如果要更改'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]