加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

关闭如何为Ruby的define_singleton_method工作?

发布时间:2020-12-17 02:09:05 所属栏目:百科 来源:网络整理
导读:这个 Ruby(2.2.3p173)代码: class A def msg "hello" end def p Proc.new { msg } end def lam lambda { msg } end def blk (1..3).map { msg }.join(" and ") end def d1(obj) obj.define_singleton_method(:say1) { msg } end def d2(obj) bound = msg #
这个 Ruby(2.2.3p173)代码:

class A
    def msg
        "hello"
    end

    def p
        Proc.new { msg }
    end

    def lam
        lambda { msg }
    end

    def blk
        (1..3).map { msg }.join(" and ")
    end

    def d1(obj)
        obj.define_singleton_method(:say1) { msg }
    end

    def d2(obj)
        bound = msg # <== Why is this needed?
        obj.define_singleton_method(:say2) { bound }
    end
end

a = A.new

puts a.p.call

puts a.lam.call

puts a.blk

obj = Object.new

a.d1(obj)

begin
# Why does this fail?
puts obj.say1
rescue
puts "caught: #{$!}"
end

a.d2(obj)

puts obj.say2

产生这个输出:

hello
hello
hello and hello and hello
caught: undefined local variable or method `msg' for #<Object:0x00000001a20638>
hello

是什么让d1和d2有所不同?为什么所有的块都会看到msg,除了传递给define_singleton_method的块?

更新:

我认为归结为:

Proc bodies have a lexical scope like functions in Lisp and
JavaScript,meaning that when Ruby encounters a free variable inside a
proc body,its value is resolved within the context the proc was
defined. This is what makes closures possible. Methods are different,
however. A method’s context is the object to which they are bound.
When Ruby encounters a free variable inside a method body,it assumes
the variable refers to another method on the object,and this is what
saves us from having to prefix same-object methods with “this” or
“self”.

我在这里找到的:Of closures,methods,procs,scope,and Ruby.

具有{msg}的所有这些各种块必须像Proc主体那样工作. define_singleton_method正在获取块并为其提供方法规则.

解决方法

答案与自我和范围有关

在ruby中创建新范围有三种方法.
类,模块和方法.

您的类创建一个范围,并且您的每个方法都创建一个包含特定于它们的绑定的范围.闭包很特别.当您定义块时,闭包将捕获周围的绑定,并且块结束后块特定绑定将消失.例如:

def my_method
  #Method scope
  x = "Goodbye"
  yield("Cruel")
end

x = "Hello"
#Closure says "I am going to grab the local bindings from my scope
my_method {|y| "#{x},#{y} world" }

什么时候编写代码

obj.define_singleton_method(:say1) { msg }

闭包抓取的唯一本地绑定是’obj’
这可以通过修改代码来证明:

def d2(obj)
   puts "in the scope of method :d2,I have acces to the :msg method: #{methods.include?(:msg)}"
   puts "---"

    obj.define_singleton_method(:say2) do 
      puts "in the scope of this closure,I have acces to the :msg method: #{methods.include?(:msg)}"
      puts "Things I do have access to: "
      puts methods
      puts local_variables
    end
  end

一个关于ruby最重要部分的简单打印声明,self,将向您显示您在不同的范围内操作.看看下面的代码:

def d2(obj)
   puts "in the scope of method :d2,I am operating as #{self}"
   puts "---"

    obj.define_singleton_method(:say2) do 
      puts "in the scope of this closure,I am operating as #{self}"
    end
end

简而言之,原因在于范围.每当你声明bound = msg时,你正在使用方法的msg本地内容,然后闭包然后可以获取msg的本地绑定值.

如果你想了解更多关于它是如何工作的,我强烈推荐“实用程序员 – 元编程Ruby”你会学到很多关于自我和闭包的知识.
http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Facets/dp/1941222129

– – 编辑 – –
“为什么是”

def p
???Proc.new {msg}
结束

不同于

def d2(obj)
??obj.define_singleton_method(:say2){msg}
结束

它是不同的,因为块内的自我是不同的.在方法定义“p”中,块可以访问实例变量和方法,而方法“d2”有一个只能访问Object的块.我们可以通过一点点monkeypatching来证明这一点.添加此代码:

class Object??def msg?????“再见”??结束

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读