吃了大力丸的Ruby 2

本文介绍了一种Ruby中的自我更新方法,该方法通过在方法内部重新定义自身来实现仅运行一次的功能,并探讨了其在记忆优化及状态模式实现等方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Why's Lucky Stiff 上看来的。俺只是搬运工。能读原文的老大们不用往下看了。

嗯,假如一个类里有个实例方法。我们希望这个方法只运行一次。”切,我还以为是抢鸡蛋呢“,熟读铁撬书的老大们开始嗤之以鼻,”不就是第391页里Tadayoshi Funaba的 once么?就 连上一篇《吃了大力丸的Ruby》也有类似的实现”:
  ids
id ids
module_eval
alias_method __
private __






那有没有其它的方法,绕开这种meta-programming的常见技巧呢?于是__Why老大提出了下面这个方法:


  Trial
run_me
run_me Exception
puts



t Trialnew
trun_me

trun_me
注意03行。在方法run_me()里,我们重新定义了run_me()。因为定义函数也是动态执行,当run_me()第一次运行时,03行被执行,导致新的run_me()被定义。接着04行被执行,打印出"Your trial period has ended"。函数run_me()执行完毕后,新定义取代老定义,再执行就得到第12行的结果了。注意03行用了 self .run_me。这样run_me()在instance的范畴内被改写,所以我们可以不断创建新的Trail实例,里面的run_me()可以运行至少一次。如果去掉self,run_me()会在class级别被重写。导致run_me()只能被第一个Trial的实例执行一次。

从上面我们还可以印证一个细节:Ruby里的 def..定义的方法的scope和执行这个定义的方法无关。执行定义的方法和被定义的方法的scope只取决于它们的context. 这点和JavaScript或Python都不一样。下面一段Ruby代码可为例证:
  foo
bar
puts

puts


bar

foo

bar

这个技术自然可以应用到记忆优化上:

01: class Hit
02: def initialize (ip )
03: @ip = ip
04: end
05: def country
06: def self .country ; @country end
07: @country = `geoiplookup # {@ip}`.chomp.gsub(/^GeoIP Country Edition: /,"")
08: end
09: end

后来有人评论道,把被记忆的数据转换成accessor速度更快。我一般对这种语言级别的优化不感冒。没有测量的情况下,再怎么也轮不到这种局部微调啊。不过考虑到Ruby现在的速度真的有点慢(那个soap4r简直要把人气死),还是值得提一下:
1: def country
2: class < < self ; attr_reader :country end
3: @country = `geoiplookup # {@ip}`.
4: chomp . gsub ( /^GeoIP Country Edition: / , "" )
5: end

为什么用attr_reader就快呢?因为生成的attr_reader被放在了包含它的类的解析树之外。用它时省去了动态查找的时间:
  X
attr_reader x
y


X
Object
defn x ivar
defn y scope block args ivar

运用自我更新的方法,还可以实现无需对象的诸如有限自动机或状态模式。是的,我没有胡言乱语。不用对象,一样可以实现状态模式。具体的实现和背后的理论,就留待下一片大力丸了。性急的老大们可以到 这里看例子。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值