首页 > 解决方案 > 为什么 class_eval 以不同的方式评估字符串和块?

问题描述

我是 ruby​​ 新手,今天我发现class_evalfor string 和 block 有一些不同的行为。例如

class A
end

class C
  A.class_eval("print Module.nesting") # [A, C]
  A.class_eval{print Module.nesting} # [C]
end

如您所见,在字符串Module.nesting打印 [A,C] 的情况下,在块的情况下它仅打印 C。

你能告诉我这是什么原因吗?

标签: ruby-on-railsrubymetaprogramming

解决方案


在第一种情况下,您将一个字符串填充到class_eval中,然后在类 A 上调用这个 class_eval。因此,当计算表达式时Module.nesting- 它需要生成它的嵌套级别 - 发现它自己在 aA中,而后者又在 a 中被计算C

在第二种情况下,您传递一个类似于 proc 对象的块。效果可媲美

 class C
   p = Proc.new { print Module.nesting }
   do_something(p)
 end

Proc 代表一个闭包,即上下文是创建 Proc 的上下文。很明显,这里的嵌套只是 C,如果你在里面计算 p,这不会改变do_something

这是一件好事。想象以下情况:

def f(p)
  x = 'f'
  p.call
end

def g
  x = 'g'
  p = Proc.new { puts x }
  f(p)
end

因为 p 的绑定发生在方法 g 内部,所以块中引用的 x 指的是x内部的局部值g,尽管f有一个同名的局部变量。因此,此处打印g 。同样,在您的示例中再现了块定义点的嵌套。


推荐阅读