ruby reflection -访问each块中的值

lc8prwob  于 11个月前  发布在  Ruby
关注(0)|答案(3)|浏览(98)

标题很弱,因为我不知道如何描述这一个。
在Ruby中,数组可以被迭代,例如(这里有一个简单的例子,但是任何参数都可以被传递

[Integer.class, String.class, Module.class].each do |_|
  puts _
end

字符串
这将返回Class\n Class\n Class
是否有可能获得每个数组对象的实际值,理想情况下是从每个块中获得?
例如Integer.class, String.class, Module.class
另一个例子,这次预期的原件是“1+1”和“2+2”,例如作为字符串,不是结果

[1+1,2+2].each do |n|
  puts n
end


你能得到“原始元素”的内容吗,例如[1+1],[2+2]?

  • 如果命令首先存储为字符串,则“命令”和“结果”可以使用类似
["1+1","2+2"].each do |n|
  puts "calculating #{n}"
  puts eval n
end


我想知道类似的东西是不是可能的(输出n),* 而不是 * 将命令存储为字符串。希望这是有意义的!

e4yzc0pl

e4yzc0pl1#

你想做什么?你希望在结束时得到什么?知道你的预期结果是什么会很有帮助。

[Integer, String, Module].each do |x|
   x
 end
=> [Integer, String, Module]

字符串
你在向Class的示例询问它的类,如果你想知道类名,那么你应该向Integer.class.name的示例询问它的名字。

tyu7yeag

tyu7yeag2#

据我所知,这是不可能做到的。当你定义一个数组与表达式像[1+1,2+2],Ruby计算这些表达式的值,并存储在数组中。在这种情况下,1+1是2,2+2是4,所以数组成为[2,4]。
如果数组是动态添加的,则将数组转换为字符串的工作方式与您所描述的一样:%w[1+1 2+2]
谢谢你

b09cbbtk

b09cbbtk3#

TL;DR

在Ruby中,几乎所有的东西都是表达式,表达式通常从左到右计算。这意味着像1+1这样的表达式在传递给你的块之前就已经传入了。所以,你要么需要单独传入表达式的每个元素,要么在你的块中将一个字面量解析成其他的东西。
作为一个更简单的替代方案,我还展示了一个如何安全地使用Kernel#eval的示例,前提是你没有迭代不受信任或受污染的数据。这稍微优雅一点,但只有当你可以保证你正在评估的对象的安全时才能安全地使用。

子数组迭代

举一个简单的例子,你可以传入子数组。假设你总是在做加法:

[[1, 2], [3, 4]].map { p _1, _2; _1 + _2 }
1
2
3
4
=> [3, 7]

字符串
或者,如果你想要每个子数组,你可以使用#tap或扩展你的#map块来打印你的子数组的元素:

[[1, 2], [3, 4]].tap { p _1, _2 }.map { _1 + _2 }
[1, 2]
[3, 4]
=> [3, 7]

解析String对象为整数和数学运算

如果你将每个元素存储为一个String对象,那么你需要先将其拆分为String和operator元素。例如:

["1+2", "2*2"].map do |str|
  str.match(/(\d+)([+-\/*])(\d+)/) do
    pp $&.to_s
    $1.to_i.send($2.to_sym, $3.to_i)
  end
end


这将打印并返回:

"1+2"
"2*2"
=> [3, 4]

关于允许强制转换的重要说明

  • 调用String#to_i是相当宽松的,所以nil或空String将计算为0。这可能不是你想要的,在这种情况下,你应该使用类似Kernel#的东西来重构值。你也可以扩展你的块来做其他验证,但重点是你应该注意String#to_i和String#to_sym的边缘情况。*

安全使用内核#eval

虽然在污染数据上不安全,但如果你只是想要最简单的东西,并且不使用用户输入或外部数据,那么eval也可以工作。例如:

h = {}
["1+2", "2*2"].map { h[_1] = eval(_1) }
# => [3, 4]

h
#=> {"1+2"=>3, "2*2"=>4}


人们会告诉你Kernel#eval是不安全的,当你处理任意数据时,它是不安全的,但在这种情况下,你 * 知道 * 传入的是什么。具体来说,你传入的是一组已知的简单数学运算,作为 * 你 * 编写的String对象,所以这是对#eval方法的完全有效的使用。
如果您正在处理不受信任的数据或用户输入,请使用其他替代方法之一,或者确保先执行某种验证和清理。这可以避免在对String调用#eval时执行任意代码。

相关问题