给定一个数组,单个元素或nil,获得一个数组 - 后两个分别是单个元素数组和一个空数组 .
我错误地认为Ruby会以这种方式工作:
[1,2,3].to_a #= [1,2,3] # Already an array, so no change
1.to_a #= [1] # Creates an array and adds element
nil.to_a #= [] # Creates empty array
但你真正得到的是:
[1,2,3].to_a #= [1,2,3] # Hooray
1.to_a #= NoMethodError # Do not want
nil.to_a #= [] # Hooray
所以要解决这个问题,我需要使用另一种方法,或者我可以通过修改我打算使用的所有类的to_a方法来进行元编程 - 这对我来说不是一个选项 .
所以它是一个方法:
result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))
问题是它有点乱 . 这样做有一种优雅的方式吗? (如果这是解决这个问题的Ruby-ish方法,我会很惊讶)
这有什么应用?为什么甚至转换为阵列?
在Rails的ActiveRecord中,调用say, user.posts
将返回一个帖子数组,一个帖子或nil . 在编写处理结果的方法时,最简单的假设该方法将采用一个数组,该数组可能包含零个,一个或多个元素 . 示例方法:
current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}
10 回答
[*foo]
或Array(foo)
大部分时间都可以工作,但是对于某些情况,例如哈希,它会混乱 .我能想到的唯一方法就是使用哈希来定义一个方法 .
Array(whatever)
应该做的伎俩ActiveSupport(Rails)
ActiveSupport有一个非常好的方法 . 它装载了Rails,所以最好的方法是:
Splat(Ruby 1.9)
splat运算符(
*
)取消对数组进行排列,如果可以的话:当然,没有数组,它会做奇怪的事情,而你“splat”的对象需要放在数组中 . 这有点奇怪,但它意味着:
如果您没有ActiveSupport,则可以定义方法:
虽然,如果你计划拥有大型数组,而不是非数组的东西,你可能想要改变它 - 上面的方法对于大型数组来说很慢,甚至可能导致你的Stack溢出(omg so meta) . 无论如何,你可能想要这样做:
我也有一些benchmarks有和没有teneray操作员 .
最简单的解决方案是使用
[foo].flatten(1)
. 与其他提议的解决方案不同,它适用于(嵌套)数组,哈希和nil
:由于存在陈述显而易见的风险,并且知道这不是地球和周围地区有史以来最美味的语法糖,因此这段代码似乎正如您所描述的那样:
由于方法
#to_a
已存在于两个主要有问题的类(Nil
和Hash
),因此只需通过扩展Object
为其余方法定义方法:然后你可以轻松地在任何对象上调用该方法:
你可以覆盖Object的数组方法
一切都继承了Object,因此to_a现在将被定义为阳光下的一切
怎么样
我已经完成了所有的答案,而且大部分都不适用于红宝石2
但是elado拥有最优雅的解决方案,即
可悲的是,这对红宝石2也不起作用,因为你会收到一个错误
所以为了解决你需要的问题 .
使用ActiveSupport(Rails):
Array.wrap
如果您不使用Rails,则可以定义类似于the rails source的自己的方法 .