gpt4 book ai didi

arrays - 为什么 Range#select 会产生一个 Array 对象?

转载 作者:太空宇宙 更新时间:2023-11-03 18:08:06 24 4
gpt4 key购买 nike

假设我有一个 Range 对象,(1..30).class # => 范围

现在考虑我正在尝试找到 num 的因数,

num = 30
factors = (1..num).select { |n| num % n == 0 }
factors.class # => Array

对于 Ruby 2.3.1,Range 对象没有 #select,但 Array 对象有。调用 Range#select 如何生成 Array 对象?

我认为我没有完全理解 Ruby 对象模型。我目前的理解是 factors.class.eql? Range 应该返回 true,而不是 false

factors.class.eql?数组 # => true

最佳答案

Ruby 中的对象模型很简单,单一继承,但具有“混合”模块以添加共享行为的能力。在您的情况下,您使用的是 select 模块 Enumerable 中存在的方法。这个模块混合成Array、Hash和Range。这给出了这些类方法的实例,例如 select。您可以在此处阅读有关可枚举方法的更多信息:https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select

如果您考虑一下,Range#select 返回一个数组是有道理的。您不是从范围中选择连续的值吗?您正在选择 block 从中返回 true 的任意值,这使得不可能返回一个范围,因此,#select 将始终返回一个数组,即使它是在 Hash 或任何其他混合类上调用的在可枚举中。

更新:

了解 Enumerable 如何从范围返回数组

要实现混合在 Enumerable 中的任何类,您只需在您的类上定义 #each 方法。假设您重新实现了 Range:

class Range
include Enumerable # mixin

def initialize(first, last)
@number_range = first.upto last # this is an array of ints
end

def each(&block) # this methods returns an enumerable
@number_range.each &block
end
end

通过上面我们可以初始化我们假设的范围实例:

@hypo_range = Range.new 1, 10

并对其调用可枚举方法:

@hypo_range.any? { |i| i == 5 } # => true
@hypo_range.select &:odd? # => [1,3,5,7,9]

因为您只需要实现#each 来挂接到 Enumerable API,无论对象的类是什么,Ruby 都知道如何处理它。这是因为在新的 #each 方法中,您已经在遍历数组了! Enumerable 在幕后使用您的 each 方法在顶部实现所有其他可枚举方法,例如any?selectfind

#each 方法是您告诉 Ruby 如何迭代对象集合的地方。一旦 Ruby 知道如何遍历您的对象,结果就已经是一个数组。

Range 的 Rubinius 实现

你可以在这里看到Range是通过使用whilefirst值循环直到到达last值和yield在每次迭代时都生成 block 。该 block 将结果收集到一个数组中,这就是您如何通过调用 Range#select 来获取数组,因为 select 正在使用 each引擎盖。

https://github.com/rubinius/rubinius/blob/master/core/range.rb#L118

一些资源:

关于arrays - 为什么 Range#select 会产生一个 Array 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40311036/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com