2014-02-10 57 views
2

Ruby中是否有創建一個元素的數組,的同一類型?Ruby:單元素類型的數組

例:

class User 
end 

my_array = UserArray.new 

我當然可以手動創建類,但我寧願有一個默認的行爲,因爲我需要它爲許多不同的類。

感謝

+0

你爲什麼需要這門課?爲什麼不'my_array = []','my_array << User.new'? – falsetru

+2

@falsetru我想,他想限制數組使用特定的元素,如集合... –

+0

如果你想要類似Java中的泛型,Ruby不支持這一點。你需要自己實現它。 – plu

回答

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

@Jeffery,我的代碼的第二部分有點棘手,我必須在發佈之前對它進行測試。 –

+0

是的,你稱之爲「第一部分」真的是一個評論。 – Shoe

+1

'Array.new(3,「12」)'會創建一個3''12「'對象的數組,它們會將相同的對象保持不變?這不可能是答案,爲什麼更多的代碼?或者可能是我沒有得到OP的重點。 –

1

我會多加一個答案,一個不解決字面OP的問題,但解決了提問者可能有問題。 User類型的主要類通常將其實例保存在某種民事登記中。也就是說,對象空間中存在一個或多個集合,其中包含用戶名稱和其他可能的ID,這些集合都可以用於唯一標識User實例。然後,我們擔心驗證對象是否是用戶或用戶標識。這種情況經常遇到,至少對於命名部分,我寫了一個寶石,y_support/name_magic。這個gem的靈感來自於Ruby中的類和模塊經常被命名,它們可以通過不斷的賦值來命名,甚至還有內置的#name方法返回它們的名字。與gem install y_support安裝name_magic和按如下方式使用它:

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. 

要完成的遊,讓我們回顧一下我們所創建的實例,並且注意到也name_magic定義的方法Array#names

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

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