0

这是代码:

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. 这是怎么回事?

4

3 回答 3

8

纯红宝石中不存在此方法。是从铁轨上来的。要使用它,您必须包含 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]vs. users.second
  2. 他们更容易。考虑改变

    users[1] to users[2]
    

    对比

    users.second to users.third
    

* 我的意思是 Active Support 带来的帮手。我更first喜欢users[0].

于 2013-05-29T18:42:10.653 回答
1

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

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

于 2013-05-29T18:47:20.807 回答
0

正如其他答案所述,此方法来自 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

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

于 2013-05-29T18:47:15.027 回答