Ruby:单一类型元素的数组

时间:2014-02-10 10:52:04

标签: ruby arrays

Ruby中有没有办法创建一个 相同类型的元素数组?

前:

class User
end

my_array = UserArray.new 

我当然可以手动创建类,但我宁愿有一个默认行为,因为我可能需要它用于许多不同的类。

由于

2 个答案:

答案 0 :(得分:1)

是什么意思?只是?喜欢这个?

class User; end
my_array = 5.times.map { User.new }

必须?喜欢这个?

class << Array
  def of klass_in_plural
    require 'active_support/inflector'    # gem install activesupport if necessary
    klass = const_get klass_in_plural.to_s.singularize
    Class.new self do
      define_method :check do
        require 'y_support/typing'        # gem install y_support if necessary
        aT_all_kind_of klass              # runtime assertion that raises TypeError unless
      end                                 # all the elements of self are #kind_of? klass

      class << self
        def [] *args; super.check end
        def new *args; super.check end
      end

      def << arg; super.check end
      def + arg; self.class.new super end
      def - arg; self.class.new super end
      # etc etc
    end
  end
end

a = Array.of( :Integers )[ 1, 2, 3 ]
#=> [ 1, 2, 3 ]
b = Array.of( :Integers )[ 1, 2, 3.3 ]
#=> TypeError: Each collection element must be kind of Integer!
c = Array.of( :Hashes )[ { a: 42 } ]
#=> [{a: 42}]
d = Array.of( :Hashes )[ 42 ]
#=> TypeError: Each collection element must be kind of Hash!
e = Array.of( :Users )[ User.new, User.new ]
#=> [#<User:0xb7cd8040>, #<User:0xb7cdaa0c>]

答案 1 :(得分:1)

我将再添加一个答案,一个不解决字面OP问题,但解决了提问者可能遇到的问题。 User类型的主要类别通常将其实例保存在某种民事登记处。也就是说,对象空间中存在一个或多个集合,其中包含用户名和可能的其他类型的ID,这些ID可以全部用于唯一标识User个实例。然后,我们关注验证对象是用户还是用户ID。经常遇到这种情况,至少对于命名部分,我写了一个gem y_support/name_magic。这个gem的灵感来自于Ruby中的类和模块经常被命名,它们可以通过常量赋值来命名,甚至还有内置的#name方法返回它们的名称。使用name_magic安装gem install y_support并按如下方式使用它:

require 'y_support/name_magic'

class User
  include NameMagic
  def to_s; "user #{name or object_id}" end
  def inspect; "#<#{self}>" end
end

# we can now construct named users easily:
u = User.new name: "Cathy"
u.name #=> :Cathy
User::Cathy #=> #<user Cathy>
# and we also have constant magic at our disposal to construct named users:
Fred = User.new #=> #<user Fred>
# By including NameMagic, User class has acquired the registry of instances:
User.instances #=> [#<user Cathy>, #<user Fred>]
# And the ability to indifferently access those instances by their ids:
User.instance( u ) #=> #<user Cathy>
User.instance( :Cathy ) #=> #<user Cathy>
User.instance( "Fred" ) #=> #<user Fred>
User.instance( :Augustin ) #=> NameError: No instance Augustin in User.
# Anonymous users can be constructed, too:
u = User.new
# And named later
u.name = "Joe"
# We can notice that although user "Cathy" is no longer explicitly assigned
# to any variable (since u contains Joe now), it is still registered in the
# @instances instance variable owned by User class and serviced by NameMagic
# mixin. So Cathy continues to live as a User instance:
User.instances #=> [#<user Cathy>, #<user Fred>, #<user Joe>]
# If we wanted Cathy garbage collected, we would have to forget her explicitly
User.forget :Cathy # returns the unnamed user Cathy for the last time
User::Cathy #=> NameError: uninitialized constant User::Cathy

此时,我通常会定义一个构造函数#User,这样我就不必一遍又一遍地输入“.new”:

def User *args, &block
  User.new *args, &block
end

一个实例访问者#user,这样我就不必一遍又一遍地输入“User.instance”:

def user user
  User.instance user
end

之后,我有能力处理实例识别和类验证的问题:

# Constructing new users:
User name: "Augustin" #=> #<user Augustin>
Quentin = User() #=> #<user Quentin>
# () is necessary to distinguish the method #User from the constant User

user :Quentin #=> #<user Quentin>
user :Arun #=> NameError: No instance Arun in User.

# I will subclass Array to define an array of users:
class Users < Array
  class << self
    def [] *args; super *args.map { |arg| user arg } end
    def new arg; super arg.map { |e| user e } end
  end
end

# And I will define conveninece constructors #Users and #users:
def Users arg; Users.new arg end
def users *args; Users[ *args ] end

# Now I have indifferent access regardless whether the elements are instances or
# instance ids (ie. names):
Users [ Fred, :Augustin ] #=> [#<user Fred>, #<user Augustin>]
# And I validate that the collection elements must be User instances or their ids:
users :Augustin, :Quentin #=> [#<user Augustin>, #<user Quentin>]
users :Augustin, :Arun # NameError: No instance Arun in User.

要完成导览,让我们查看我们创建的实例,并注意Array#names定义的方法name_magic

users = User.instances
#=> [#<user Fred>, #<user Joe>, #<user Augustin>, #<user Quentin>]

user_names = users.names
#=> [:Fred, :Joe, :Augustin, :Quentin]