Ruby:从Array类中提取Stack的function

我需要为我正在编写的程序使用类似堆栈的数据结构,并且我知道Ruby没有显式的堆栈数据结构,但是Array类具有构成堆栈的所有属性: pushpopsizeclearisEmptyinspectto_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中。

问题:

  1. 这个function被删除是有原因的,这样的事情有什么不利?
  2. 如何使用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#pushStack#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