为什么我在数组中得到第二个,第三个对象的奇怪行为?

时间:2013-05-29 18:39:49

标签: ruby

以下是代码:

class Person
  attr_accessor :id, :name

  def initialize(init = {})
    init.each do |k, v|
      send("#{k}=", v)
    end
  end
end

people = [ 
  Person.new(:id => 1, :name => "Adam"), 
  Person.new(:id => 2), 
  nil,
]

people.map! do |person|
  person ||= Person.new(:id => 3, :name => "Some default")
  person.name ||= 'Eve'
  person
end

binding.pry

这就是我得到的东西:

[1] pry(main)> people
=> [#<Person:0x007fc2b0afba98 @id=1, @name="Adam">,
 #<Person:0x007fc2b0afb930 @id=2, @name="Eve">,
 #<Person:0x007fc2b0afb7f0 @id=3, @name="Some default">]
[2] pry(main)> people.first
=> #<Person:0x007fc2b0afba98 @id=1, @name="Adam">
[3] pry(main)> people.second
NoMethodError: undefined method `second' for #<Array:0x007fc2b0afb890>
from (pry):3:in `<main>'

我原本希望能够访问people.secondpeople.second.id。怎么了?

3 个答案:

答案 0 :(得分:7)

普通红宝石中不存在此方法。它来自铁轨。要使用它,您必须包括Active Support。

require 'active_support/core_ext'

a = [4, 5, 10]

a.first # => 4
a.second # => 5
a.third # => 10

但你真的不应该习惯以这种方式访问​​数组元素。出现first / last个助手是有原因的:通常只需要第一个或最后一个元素。

user = User.where(name: 'Sergio').first # user might not exist
last_transaction = user.transactions.last

如果您打算访问第二,第三,第四(和更多)元素,那么有更好的选择。例如,使用.each进行迭代。

user.transactions.each do |tran|
  # ...
end

我个人更喜欢索引器而不是这些帮助器*(即使它们可用)。

  1. 索引器表单较短(users[1]users.second
  2. 他们更容易。考虑改变

    users[1] to users[2]
    

    VS。

    users.second to users.third
    
  3. *我的意思是Active Support带来的帮助。我更喜欢first而不是users[0]

答案 1 :(得分:1)

只需使用people[1],这是访问数组中元素的标准方法。

要求“active_support / core_ext”添加了许多你可能不需要的东西,而这些东西相当于非常少量的语法糖。

答案 2 :(得分:0)

正如其他答案所述,此方法来自Active Support。但是如果你不想仅针对一种方法引入Active Support ......好吧,这是Ruby,不是吗?

class Array
  def second
    self[1]
  end
end

或者,更一般地说:

module Enumerable
  def second
    first = true
    each { |x| first ? (first = false) : return x }
  end
end

您实际上可以包含这两个定义,对于Arrays,将使用更具体(也可能更快)的方法。对于其他类型的Enumerables,将使用更通用的方法。