Struct从reader和hash访问器返回不同的东西

时间:2012-12-04 07:00:18

标签: ruby

我有这样的结构:

class Item < Struct.new(:url, :list)
  def list
    @list ||= Array.new
  end
end

我今天发现.list()[:list]会返回不同的内容:

i = Item.new
#=> #<struct Item url=nil, list=nil>
i.list
#=> []
i[:list]
#=> nil
i.list << 1
#=> [1]
i.list += [2]
#=> [1, 2]
i.list
#=> [1]
i[:list]
#=> [1, 2]

为什么这样,我如何编写我的结构以正确地使用默认空数组?

4 个答案:

答案 0 :(得分:2)

有人已经回答了“为什么”这一点,所以如果您仍然希望使用Struct执行此操作,那么为什么不尝试这样做:

class Item < Struct.new(:url, :list)
  def list
    self[:list] ||= Array.new
  end
end

这是有效的,因为@list是你制作的实例变量,Struct提供它的访问者是自己的。 (:list)。 self[:list]让你了解它。

i = Item.new # =>  #<struct Item url=nil, list=nil>
i.list   # => []
i[:list] # => []
# Compare using OBJECT IDENTITY (is i.list internally the same thing as i[:list]?)
i[:list].equal? i.list # true
i.list << 1   # => [1]
i.list += [2] # => [1, 2]
i.list        # => [1, 2]
i[:list]      # => [1, 2]

答案 1 :(得分:1)

我认为你最好使用Dash代替Struct。看:

require 'hashie'

class Item < Hashie::Dash
  property :url
  property :list, default: []
end

i = Item.new # => #<Item list=[]>
i.list # => []
i[:list] # => []
i.list << 1 # => [1]
i.list += [2] # => [1, 2]
i.list # => [1, 2]
i[:list] # => [1, 2]

答案 2 :(得分:1)

Sergio Tulentsev answered how can I write my struct to have default empty array properly?部分,所以我会写Why is this?部分。
我缺少信息,但有一个结构,它写成::new creates a new class, named by aString, containing accessor methods for the given symbols.

因此,您拥有:list的访问者,但它仍与您的@list属性不同。这意味着,您可以根据需要命名@list,它不会附属于结构的:list
您还可以覆盖结构先前使用def list; end

提供的符号访问器
i.list << 1   # adding 1 to @list set to Array.new
#=> [1]
i.list += [2] # equals i.list = i.list + [2]
              # i.list= is the `:list` setter method.
              # i.list is the @list getter method.
              # It equals :list = @list + [2]
#=> [1, 2]
i.list        # @list
#=> [1]
i[:list]      # :list
#=> [1, 2]

答案 3 :(得分:1)

假设您需要Struct的其他优点并且需要坚持使用它,您可以编写自己的initialize方法:

class Item < Struct.new(:url, :list)
  def initialize(url, list = nil)
    self.url  = url
    self.list = Array(list)
  end
end

Array()将确保传入的任何内容都将放入数组中(如果它不是已存在的数据),如果[]是参数,则会返回一个空数组(nil)。