Ruby instance_exec 和 instance_eval 有啥区别啊?

davidqhr · 2012年03月30日 · 最后由 zw963 回复于 2017年03月06日 · 6290 次阅读

还有 class_exec 和 class_eval 求解释,求例子啊~ 先谢过各位~

The Ruby Programming Language p270:

8.2.3 instance_exec and class_exec

Ruby 1.9 defines two more evaluation methods: instance_exec and class_exec (and its alias, module_exec). These methods evaluate a block (but not a string) of code in the context of the receiver object, as instance_eval and class_eval do. The difference is that the exec methods accept arguments and pass them to the block. Thus, the block of code is evaluated in the context of the specified object, with parameters whose values come from outside the object.

exec 只能接代码块,不能接字符串,eval 二者皆可 exec 作为方法可以接受参数,然后把它接受的对象传递给代码块,同时把传递对象的环境也带进了 exec 的代码块

#2 楼 @FenRagwort 我看到的资料上页是说道了 exec 可以接受参数,能整个具体例子给小弟看看不? exec 只能接受代码块我才知道,我以为这东西也能接字符串呢。

o = Object.new
o.instance_exec(123) {|x| p x }

额,好神奇。。。

只有当你遇到问题时候,提这样的问题才有意义!

googya 呵呵,也是,不过不知到有这么回事,遇见问题就根本想不到这东西。

这是官方文档 http://ruby-doc.org/core-1.8.7/Object.html 第一 其实这两个函数的在功能上的区别很大 block 参数的内容通常是固定的,比如

instance_exec {|x| p x }

而 string 参数的内容可以是动态产生的, 可以产生无限的可能性,比如

instance_eval "#{y} x"

y变量,可能是任何函数名,极度危险。

第二 instance_eval 的 string 参数,导致 动态的代码可读性很差, 相比之下,instance_exec的 block 参数,可读性很强

结论 当两者都能满足需求的时候,尽可能使用 block 参数方式, 因为这样代码可读性很强,而且还易于 debug。 只有在迫不得已的情况下,才使用 instance_eval 的 string 方式。

妹啊,我今天刚在总结这个,你就提问了。

instance_exec 与 instance_eval

两者都是取出 singleton_class 来执行 block,所以用其定义的方法全为 singletion_method instance_exec 可以传送参数,而 eval 不可以

class_eval 和 class_exec 也是执行 block,但是是放入当前 class/module 环境中执行,所以用其定义的方法为实例方法。 module_eval==class_eval

昨天和 zw96 讨论了一下,还补充一下。

instance 和 class_eval 的 recvier 都还是 self,但值得注意的是 instance_exec 的执行环境在 singleton_class 之下,而 class_eval 则在 self 之下。

所以涉及到消息接收时,两者一样,如

O.instance_exec {
  define_method(:hello) {p 'instance exec method'}
  puts self.object_id
}

O.class_exec {
  define_method(:hello1) {p 'class_exec exec method'}
  puts self.object_id
}


但涉及到执行环境时,则处理不一样,因为 instance_exec 在 singleton_class 环境下,所以生成的方法为类方法,而 class_exec 则为实例方法。

O.instance_exec {
  def fun;end
}
O.class_exec {
  def fun;end
}


好奇有啥场景用这个。。。

#10 楼 @xds2000 比如你要把 block 注入成一个 method

class App def self.helper(name, &block) define_method(name) do |*args| instance_exec(*args, &block) end end end

App.helper(:foo) {|bar| p bar} App.new.foo('bar')

#10 楼 @xds2000 很多 gem 用到,为了暴露更好的接口给这些开发者。一般开发者是很少用着的。

#11 楼 @doitian 你如果只达到这个功能,这么写不就可以了吗

def self.helper(name, &block)
      define_method(name,&block)
  end

@doitian @hhuai 致敬,学习了。

#12 楼 @hhuai 确实,例子举得不够好

#9 楼 @hhuai 兄弟,晕死。我真是服了你啦~~

难道牛人都是这样么?心里和明镜似的,只要如果让你给别人讲出来,总把简单问题复杂化... 咋俩昨天说那么明白了。怎么你回复的帖子和你发布的很多算法一样,我还是看不懂呢?(虽然绝对是正确的)

昨天和 zw96 讨论了一下,还补充一下。

另外,把俺的论坛 id 你都能少打一个 3. 汗~

instance 和 class_eval 的 recvier 都还是 self

receiver 你打成了 recvier.

汗~~, 对于一知半解的新人,我估计一看你的讲解,立马晕倒。

@zw963 哈哈,我是新人,我看晕了。 “但涉及到执行环境时,则处理不一样,因为 instance_exec 在 singleton_class 环境下,所以生成的方法为类方法,而 class_exec 则为实例方法。” 这里能否在讲解下,谢谢。

@ruby_xi , 这是引用那里的内容?

其实 instance_exec 和 class_exec 两者区别,就是使用 def 定义方法时,前者在对象的 singleton class, 后者在对象的 class 之上。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号