首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >instance_eval是如何工作的?为什么DHH讨厌它?

instance_eval是如何工作的?为什么DHH讨厌它?
EN

Stack Overflow用户
提问于 2010-06-19 00:43:50
回答 3查看 5.2K关注 0票数 22

his RailsConf presentation的19:00左右,David Heinemeier Hansson谈到了instance_eval的缺点

在很长一段时间里,我对instance_eval大加抨击,这是一个不使用产出式参数(如do |people|)而只是直接使用do something的概念,然后在您来自的范围内评估该块中的内容(我甚至不知道这是否是一个连贯的解释)。

在很长一段时间里,我不喜欢这样,因为在某种意义上,它感觉更复杂。如果你想把你自己的代码放进去,你会触发一些已经存在的东西吗?你是不是要重写什么?当你产生一个特定的变量时,你可以把所有的东西都链接起来,这样你就可以知道你没有弄乱任何人的东西

这听起来很有趣,但首先我不知道instance_eval是如何工作的,b)我不明白为什么它会变得不好/增加复杂性。

有人能解释一下吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-06-19 01:51:02

instance_eval所做的事情是在另一个实例的上下文中运行该块。换句话说,它改变了self的含义,这意味着它改变了实例方法和实例变量的含义。

这造成了认知上的脱节:区块运行的上下文并不是它出现在屏幕上的上下文。

让我通过@Matt Briggs的示例的一个微小变化来演示这一点。假设我们正在构建一个电子邮件,而不是一个表单:

代码语言:javascript
复制
def mail
  builder = MailBuilder.new
  yield builder
  # executed after the block 
  # do stuff with builder 
end

mail do |f|
  f.subject @subject
  f.name    name
end

在本例中,@subject是对象的实例变量,name是类的方法。您可以使用良好的面向对象分解,并将主题存储在一个变量中。

代码语言:javascript
复制
def mail &block
  builder = MailBuilder.new
  builder.instance_eval &block
  # do stuff with builder 
end

mail do 
  subject @subject
  name    name # Huh?!?
end

在本例中,@subject是邮件构建器对象的实例变量!它可能根本不存在!(或者更糟糕的是,它可能存在并包含一些完全愚蠢的值。)您无法访问对象的实例变量。那么如何调用对象的name方法呢?每次您尝试调用它时,都会得到邮件构建器的方法。

基本上,instance_eval使得在DSL代码中使用您自己的代码变得困难。因此,它真的应该只在几乎不需要它的情况下使用。

票数 33
EN

Stack Overflow用户

发布于 2010-06-19 00:55:43

好的,这里的想法不是这样的

代码语言:javascript
复制
form_for @obj do |f|
  f.text_field :field
end

你会得到像这样的东西

代码语言:javascript
复制
form_for @obj do 
  text_field :field
end

第一种方法非常简单,您最终得到的模式如下所示

代码语言:javascript
复制
def form_for
  b = FormBuilder.new
  yield b
  b.fields.each |f|
    # do stuff
  end
end

您生成一个构建器对象,消费者在该对象上调用方法,然后调用构建器对象上的方法来实际构建窗体(或其他任何东西)

第二个更神奇一点

代码语言:javascript
复制
def form_for &block
  b = FormBuilder.new
  b.instance_eval &block
  b.fields.each |f|
    #do stuff
  end
end

在这个示例中,我们不是将构建器交给块,而是在构建器的上下文中对其进行评估

第二个问题增加了复杂性,因为你是在玩有范围的游戏,你需要理解这一点,消费者需要理解这一点,编写你的构建器的人也需要理解这一点。如果每个人都持相同的观点,我不知道这必然是一件坏事,但我确实质疑收益与成本,我的意思是,在你的方法前面添加一个f有多难?

票数 17
EN

Stack Overflow用户

发布于 2010-06-19 16:20:55

这个想法是有点危险的,因为如果你不阅读所有处理你使用instance_eval的对象的代码,你永远不能确定你不会破坏一些东西。

另外,如果你更新了一个库,这个库没有太多地改变接口,但是改变了很多对象的内部结构,那么你可能真的会造成一些破坏。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3071532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档