Ruby on rails Ruby(猴子补丁阵列)

Ruby on rails Ruby(猴子补丁阵列),ruby-on-rails,arrays,ruby,rspec,Ruby On Rails,Arrays,Ruby,Rspec,回来寻求更多关于我在Bloc课程的帮助。决定把你们带到我遇到的一个关于猴子修补数组类的问题上。这项任务有8个规格需要满足,我现在只剩下一个,我不知道该怎么办 我只想给你我遇到麻烦的部分的RSpec和书面要求,因为其他一切似乎都通过了。此外,我还将包括他们给我的入门支架,这样就不会对代码造成混淆或无用的添加 以下是阵列类Monkey补丁的书面要求: 编写一个新的new\u map方法,该方法在Array类的实例上调用。它应该使用调用它的数组作为隐式(self)参数,但在其他情况下行为相同。(不

回来寻求更多关于我在Bloc课程的帮助。决定把你们带到我遇到的一个关于猴子修补数组类的问题上。这项任务有8个规格需要满足,我现在只剩下一个,我不知道该怎么办

我只想给你我遇到麻烦的部分的RSpec和书面要求,因为其他一切似乎都通过了。此外,我还将包括他们给我的入门支架,这样就不会对代码造成混淆或无用的添加


以下是阵列类Monkey补丁的书面要求:

  • 编写一个新的
    new\u map
    方法,该方法在
    Array
    类的实例上调用。它应该使用调用它的数组作为隐式(
    self
    )参数,但在其他情况下行为相同。(不完整

  • 写一个新的选择!方法的行为类似于select,但会对调用它的数组进行变异。它可以使用Ruby内置的集合选择方法。(完成


以下是有关阵列类需要满足的RSpec:

注意:“返回具有更新值的数组”是唯一未通过的规范


最后,这是我的代码:

class Array
  def new_map 
    new_array = []
    self.each do |num|
      new_array << num.to_s
    end
    new_array
  end

  def new_select!(&block)
    self.select!(&block)
  end
end
类数组
def新地图
新的_数组=[]
self.each do|num|

新的_数组查看此处的规范:

it "returns an array with updated values" do
  array = [1,2,3,4]
  expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
  expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
看起来他们只是想让您重新编写
Array.map
,以便它可以处理任何给定的块。在您的实现中,您告诉该方法以一种非常特定的方式工作,即对所有数组元素调用
。但您不希望它总是字符串化数组元素。您希望它对每个元素执行调用方法时提供的任何块。试试这个:

class Array
  def new_map 
    new_array = []
    each do |num|
      new_array << yield(num)
    end
    new_array
  end
end
类数组
def新地图
新的_数组=[]
每个do | num|
新阵列
Ruby数组类:

map { |item| block } → new_ary
类似于方法,您可以在方法调用后指定块,例如:

[1, 2, 3].map() {|x| x*2} #<---block
           ^
           |
       method call(usually written without the trailing parentheses)
此注释有点高级,但实际上不必编写
self.each()
来调用new\u map()中的each()方法。所有方法都由某个对象调用,即点左侧的对象,称为接收器。例如,当您编写:

self.each {....}
self是方法调用each()的接收者

如果不指定
接收器
,只需写下:

each {....}
…然后对于接收器,ruby使用当时分配给
self
变量的任何对象。在上面的new_map()中,ruby将把调用new_map()方法的数组分配给self,因此每个()都将遍历该数组中的项

您必须对自变量稍微小心一点,因为ruby不断地更改自变量的值而不告诉您。因此,您必须知道ruby在代码中的任何特定点上为self变量指定了什么——这是经验所带来的。尽管如此,如果您想知道ruby在代码中的某个特定点分配给self的对象是什么,您可以简单地编写:

puts self
如果有经验的rubyists看到你在new_map()中编写
self.each{…}
,他们会大喊大叫,但在我看来代码清晰性胜过代码欺骗性,因为初学者在那里编写self更有意义,那就去做吧。当你获得了更多的经验并且想要炫耀时,你可以在不需要显式接收者的时候消除它们。这与显式返回的情况类似:

def some_method
    ...
    return result
end
def some_method
    ...
    result
end
和隐含回报:

def some_method
    ...
    return result
end
def some_method
    ...
    result
end
请注意,您可以这样编写新的_map():

class Array
  def new_map(&my_block)  #capture the block in a variable
    result = []

    each do |item|
      result << my_block.call(item) #call the block
    end

    result

  end
end

arr = [1, 2, 3].new_map {|x| x*2}
p arr

--output:--
[2, 4, 6]
class Array
  def new_select!(&block)
    replace(select(&block)) 
  end
end
类数组
def new_map(&my_block)#在变量中捕获块
结果=[]
每个do |项目|

结果我想说几句关于
new\u select

选择vs选择

你有:

class Array
  def new_select!(&block)
    self.select!(&block)
  end
end
你可以这样写:

class Array
  def new_select!
    self.select! { |e| yield(e) }
  end
end
这就使用了这个方法。你说可以使用,但没有提到
select。如果无法使用
选择,必须执行以下操作:

class Array
  def new_map(&my_block)  #capture the block in a variable
    result = []

    each do |item|
      result << my_block.call(item) #call the block
    end

    result

  end
end

arr = [1, 2, 3].new_map {|x| x*2}
p arr

--output:--
[2, 4, 6]
class Array
  def new_select!(&block)
    replace(select(&block)) 
  end
end
让我们试试看:

a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
  #=> [1, 3, 5] 
a #=> [1, 3, 5] 
enum0 = a.select!
  #=> #<Enumerator: [1, 2, 3, 4, 5]:select!>
显性接收者与隐性接收者的对比

请注意,我写这篇文章时没有为方法和
数组选择任何显式接收器。当没有显式接收器时,Ruby假设它是
self
,即
a
。因此,Ruby对
replace(select(&block))
进行评估,就好像它是用显式接收器编写的:

self.replace(self.select(&block)) 
由您决定是否包含
self.
。有些红宝石有,有些没有。您会注意到,
self.
不包含在Ruby中实现的Ruby内置方法中。还有一件事:
self.
在某些情况下是必需的,以避免歧义。例如,如果
taco=
是实例变量
@taco
的setter,则必须编写
self.taco=7
,告诉Ruby您引用的是setter方法。如果您编写
taco=7
,Ruby将假定您想要创建一个局部变量
taco
,并将其值设置为7

选择的两种形式

你的方法是新的吗直接替换
选择?也就是说,这两种方法在功能上是等价的吗?如果您查看
数组的文档,请选择,您将看到它有两种形式,一种是您模仿的,另一种是您尚未实现的

如果
选择
未给定块,它返回一个枚举数。你为什么要这么做?假设你想写:

a = [1,2,3,4,5]
a.select!.with_index { |n,i| i < 2 }
  #=> [1, 2] 
现在:

这五个元素中的每一个都被传递到块并分配给块变量(调用)

够了,但关键是,让方法在没有给出块的情况下返回枚举数是允许我们使用c语言的
enum1.to_a
  # => [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]
class Array
  def new_select!(&block)
    if block_given?
      replace(select(&block))
    else
      to_enum(:new_select!)
    end
  end
end
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
  #=> [1, 3, 5] 
a #=> [1, 3, 5] 

a = [1,2,3,4,5]
enum2 = a.new_select!
  #=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!> 
enum2.each { |n| n.odd? }
  #=> [1, 3, 5] 
a #=> [1, 3, 5]

a = [1,2,3,4,5]
enum2 = a.new_select!
  #=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!> 
enum2.with_index.each { |n,i| i>2 }
  #=> [4, 5] 
a #=> [4, 5]