Ruby:从Array类中提取Stack的function
我需要为我正在编写的程序使用类似堆栈的数据结构,并且我知道Ruby没有显式的堆栈数据结构,但是Array类具有构成堆栈的所有属性: push
, pop
, size
, clear
, isEmpty
, inspect
, to_s
。
在线搜索我发现使用这种语法的各种post将Array类的function提取到子类中:
Stack = Array.extract([ :push, :pop, :size, :clear, :inspect, :to_s ]) s = Stack.new s.push 1 s.push 2 s.push 3 s # => [1, 2, 3] s.pop # => 3 s # => [1, 2]
我想做类似的事情,所以我的Array子类在它可以进行的调用中受到限制,但似乎提取方法不再在Array类API中。
问题:
- 这个function被删除是有原因的,这样的事情有什么不利?
- 如何使用Ruby 1.9.3实现与此类似的function? 现在我只是将我需要的调用委托给Array类,但Array类中的所有其他方法仍然可以在我的Stack对象上调用,我不想允许。
拿这个代码,例如:
class Stack def initialize @array = [] end def push val @array.push val end def pop @array.pop end end
这里有私有实例var,您可以将所选方法委派给它。 其他方法不能直接调用。 语法可以变甜,并通过一些元编程更加“rubesque”,但基本思想如上所示。
当然,总是可以通过instance_variable_get
来访问私有var,并且你无能为力。 这是Ruby!
制作干净安全的公共界面。 如果有人试图干涉内在部分并打破某些东西,那就是他的问题。
更新
如果您正在使用ActiveSupport(随Rails一起提供),那么有一种更简单的方法。
# load ActiveSupport if not in Rails env require 'active_support/core_ext' class Stack def initialize @impl = [] end # the "extract" part :) delegate :count, :push, :pop, to: :@impl end s = Stack.new s.push(3).push(4) s.count # => 2
或者看看@AndrewGrimm的类似答案 。
如果你要进行大量的委托,那么你可能想要使用Ruby提供的委托方法。
require "forwardable" class Stack extend Forwardable def_delegators :@array, :push, :pop def initialize @array = [] end end
这不仅意味着更少的打字,而且如果你熟悉Forwardable
,它更容易阅读。 你知道你的类只是委托,而不必阅读Stack#push
或Stack#pop
的代码。
也许你可以取消定义你不喜欢的方法,虽然它看起来很有线。
class Stack < Array DISLIKE_IMS = instance_methods - Object.instance_methods - [:public, :pop, :size, :to_s, :inspect, :clear] DISLIKE_CMS = methods - Object.methods DISLIKE_IMS.each do |im| class_eval "undef #{im}" end DISLIKE_CMS.each do |cm| instance_eval "undef #{cm}" end end