设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
楼主: DeathKing
打印 上一主题 下一主题

[讨论] Ruby/RGSS Tips 每日一更 [技术区的版聊帖?]

  [复制链接]

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
2
发表于 2010-9-2 10:06:13 | 显示全部楼层
2010-09-02 Proc.new 和 lambda
Proc 是 procedure 的简称,意味着一个过程,或者例程。我们基本上可以把 Ruby 的 Proc 对象看作是 Ruby 的匿名函数,但在 Ruby 1.8 中,通过不同方法获取的 Proc 对象有微妙的区别:
  1. def foo
  2.   local = 'This is a local variable'
  3.   $proc = Proc.new { return }
  4.   $proc.call # OK
  5.   p '这里永远不会执行'
  6. end

  7. foo
  8. $proc.call # error
复制代码
在 foo 方法内部,$proc 执行后,直接结束了函数的运行,而在方法外部调用 $proc 则会产生非局部跳转的异常,这里的意思是告诉你不能在顶层 return。从这个现象可以得出结论:Proc.new 会绑定创建时的上下文,而在这个 Proc 对象内 return 则是与该上下文绑定的。比如,上面的代码中,$proc 创建时的上下文是 foo 方法的局部上下文,在方法内部调用 $proc 时 foo 的局部上下文还存在(方法还没有返回),所以没有问题;在方法外部调用 $proc 时 foo 的局部上下文已不复存在(方法已经返回),所以发生了异常
我们再来看看闭包的定义:
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

然而 Proc.new 产生的 Proc 对象并没有真正的自由,它与创建时的上下文绑定在了一起,并不是一个独立的匿名函数个体(因为不能自由地 return,且成功 return 后会让外部的函数返回),所以它并不算是真正意义上的闭包
可喜的是,刁钻古怪的 Ruby 还是用一种隐晦的方式提供给了我们真实的闭包。把上面的代码中的 Proc.new 替换为 lambda 后,就能发现没有错误了。lambda 是 Kernel 里的方法,这个名称来源是 λ-calculus 中的 λ 符号,意味着一种匿名函数演算法,由 Scheme 语言最早支持,后来被各种语言继承。lambda 产生的 Proc 对象,其内部 return 是从当前的 Proc 对象,即当前的闭包返回,所以 lambda 产生的 Proc 对象才是 Ruby 真正的闭包
这里还有最后一个问题,就是 Ruby 1.8 对 proc 和 lambda 的定义产生了混淆。proc 也是 Kernel 里的一个方法,其文档中表示 Kernel#proc 等价于 Proc.new,但当我们实际把上面代码中的 Proc.new 替换为 proc 时,会发现没有异常。实际上在 Ruby 1.8 中,Kernel#proc 是等价于 Kernel#lambda 的,也就是说 Kernel#proc 也是真实的闭包。然而从命名上来看,proc 和 Proc.new 不同而合 lambda 相同,是一个很明显的设计失误,所以在 1.9 中,Ruby 巧妙地让 Proc.new 等价于了 Kernel#proc

点评

这个地方说的有歧义,应该换一下顺序,proc 等价于了 Proc.new,也就是并非真正的闭包  发表于 2010-9-26 21:54
【所以在 1.9 中,Ruby 巧妙地让 Proc.new 等价于了 Kernel#proc】的意思是说,Proc.new变成真正的闭包,而不需要lambda了?  发表于 2010-9-26 17:03
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
1
发表于 2010-8-26 10:55:10 | 显示全部楼层
有人会问:Ruby 没有析构方法?乍一看似乎这个真没有,其实这个可以有——
define_finalizer  ObjectSpace.define_finalizer( anObject, aProc=proc() )  

Adds aProc as a finalizer, to be called when anObject is about to be destroyed.  

ObjectSpace.define_finalizer 可以为某个对象添加一个类似 C++ 析构函数的最终化处理器,如果在 initialize (类似构造函数)中调用这个方法,就能为每个实例添加一个固定的析构方法
例:

  1. class MySprite < Sprite
  2.     def initialize(viewport = nil)
  3.         super(viewport)
  4.         ObjectSpace.define_finalizer(self, proc { self. dispose })
  5.     end
  6. end
复制代码
这样一来,当 MySprite 对象被回收时,精灵资源会自动释放

点评

moy
上的就是信息技术专业...准备朝编程方向发展,主要是蛮感兴趣的说~不过糟糕的是我数学不太好于是在起跑线上就被拉后腿了T_T  发表于 2010-8-28 01:20
@moy:呵呵,慢慢来~其实我觉得如果不想主走成程序的路没必要钻研太深,还是找朋友合作比较好,就像我不可能从头学美术一样……  发表于 2010-8-27 09:16
补充:Proc 还不是 Ruby 真正的闭包,lambda 才是,详见:[url]http://bbs.66rpg.com/forum.php?mod=viewthread&tid=153979[/url]  发表于 2010-8-27 09:15
moy
不管是内容还是点评一概都雾水了@_@,我还有很长的路要走啊.....好多概念都空白呢  发表于 2010-8-27 07:25
没错,实际上就是闭包的概念  发表于 2010-8-27 01:19
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-5-4 01:50

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表