我希望我的SomeArray#map
返回SomeArray
类的“数组”。
class SomeArray < Array
def map
SomeArray.new(super)
end
end
some_array = SomeArray.new(["foo", "bar", "baz"])
p some_array.class #=> SomeArray
p some_array.map { |e| e }.class #=> SomeArray
除此之外我还希望能够使用Enumerator#with_index
实例方法。理想情况下这样的事情会起作用:
some_array.map.with_index { |e, i| e }.class #=> SomeArray
那怎么办?
我试过了:
class SomeArray < Array
def map
SomeArray.new(super)
end
def with_index(offset = 0)
super
end
end
some_array = SomeArray.new(["foo", "bar", "baz"])
p some_array.class #=> SomeArray
p some_array.map.with_index { |e, i| e }.class #=> no implicit conversion of Enumerator into Integer (TypeError)
但它不起作用。
答案 0 :(得分:1)
我认为这里的问题是你将可枚举和数组视为相同,而不是它们。
具体来说,这是在地图调用中:SomeArray.new(super)
。
我可以重现你的错误:
[6] pry(main)> Array.new [1].map
TypeError: no implicit conversion of Enumerator into Integer
现在,当您将一个块传递给map
时,它可以正常工作:
Array.new([1].map { |x| x })
=> [1]
但在你的map.with_index
中,你没有这样做。
您可以这样做:
module Foo
include Enumerable
def map
puts "calling my map"
super
end
def with_index
puts "calling my with_index"
super
end
end
class MyArr < Array
include Foo
end
puts MyArr.new([1]).map.with_index { |x, y| [x,y] }
# calling my map
# calling my with_index
# 1
# 0
问题是为什么你要编写这个只调用super
的类的问题。但是如果要修改枚举的默认功能,这是一种方法。
答案 1 :(得分:1)
主要问题是map
是一种数组方法,而with_index
是一种Enumerator
方法。
super
,并将输出数组转换为SomeArray
。to_enum
定义枚举器方法,将输出转换为数组,然后转换为SomeArray
。它可能不是你想要做的最好的结构,也不是很有效。这只是一个概念证明!
class SomeArray < Array
# Array methods are overwritten here :
[:map, :select, :reject].each do |array_method_name|
define_method array_method_name do |*p, &block|
SomeArray.new(super(*p, &block).to_a)
end
end
# Enumerator methods are defined for SomeArray here :
[:with_index, :with_object].each do |enum_method_name|
define_method enum_method_name do |*p, &block|
SomeArray.new(to_enum.public_send(enum_method_name, *p, &block).to_a)
end
end
end
some_array = SomeArray.new(%w(foo bar baz biz))
p some_array.map { |s| s * 2 }.with_index.select { |_, i| i.even? }
#=> [["foofoo", 0], ["bazbaz", 2]]
p some_array.map { |s| s * 2 }.with_index.select { |_, i| i.even? }.class
#=> SomeArray