Ruby 块(需要解决方案)
Ruby blocks (need a solution)
问题是这样的:
Write in the class Range method todown behaves like this (use block_given? and yield functions):
(3..5).todown {|i| print "hi#{i} "} #prints hi5 hi4 hi3
(2...7).todown #prints 65432
经过至少一个小时的谷歌搜索,我仍然无法解决这个问题。我已经做到了这一点:
class Range
def todown
to_a.reverse.each do |i|
yield(i)
end
end
end
我不知道在哪里添加 (2..7).todown
行以获得所需的结果。
你可以使用类似这样的东西,通过使用 to_a
将范围变成一个数组,然后使用 reverse_each
在给定块时产生。
否则,我们将打印它。
class Range
def todown
reverse_each do |v|
yield v if block_given?
print v unless block_given?
end
end
end
你有没有尝试过类似的东西:
(3..5).reverse_each { |i| print "hi#{i} " }
您还可以通过以下方式修补 Range:
class Range
def todown
reverse_each do |i|
if block_given?
yield i
else
print i
end
end
end
end
这样你就可以做到:
(3..5).todown { |i| print "hi#{i} " }
编辑:
我知道这个问题只是一个练习,但是在修改 Ruby 的核心 classes 时应该非常小心。 Here 是讨论 "money-patching" 的危险以及可将风险降至最低或在核心 class 补丁爆炸时使调试更容易的步骤的众多文章之一。
我们现在有一个(有点争议的)替代方案,叫做 "Refinements"。 Refinements 是对 v2.0 的实验性补充。然后在 v2.1 中对其进行了修改并永久保留。这是它在这里的工作方式。
首先,我们refine
一个模块中的class:
module M
refine Range do
def todown
reverse_each do |i|
case block_given?
when true then yield(i)
else print i
end
end
puts
end
end
end
让我们试试看:
(2...7).todown
#-> NoMethodError: undefined method `todown' for 2...7:Range
糟糕!我们已经创建了优化,但还没有激活它。为此,我们使用关键字 using
:
using M
(2...7).todown
#-> 65432
(3..5).todown { |i| print "hi#{i} " }
#-> hi5 hi4 hi3
我在细化中添加了方法,但您可以添加、修改、重命名或删除现有实例或 class 方法,添加常量等。
最后一件事:改进似乎在 IRB 中不起作用。
:tidE]
你可以这样做:
class Range
def todown
f,l = first,last
l -= 1 if exclude_end?
if block_given?
while l >= f
yield(l)
l -= 1
end
else
s = ''
while l >= f
s << l.to_s
l -= 1
end
puts(s)
end
end
end
(2...7).todown
#-> 65432
(3..5).todown { |i| print "hi#{i} " }
#-> hi5 hi4 hi3
虽然有点长,但您会看到大多数 Ruby 的内置方法(用 Ruby 编写,而不是用 C 编写)都是以类似的方式构造的,尽可能减少对其他 classes.
方法的依赖
问题是这样的:
Write in the class Range method todown behaves like this (use block_given? and yield functions):
(3..5).todown {|i| print "hi#{i} "} #prints hi5 hi4 hi3
(2...7).todown #prints 65432
经过至少一个小时的谷歌搜索,我仍然无法解决这个问题。我已经做到了这一点:
class Range
def todown
to_a.reverse.each do |i|
yield(i)
end
end
end
我不知道在哪里添加 (2..7).todown
行以获得所需的结果。
你可以使用类似这样的东西,通过使用 to_a
将范围变成一个数组,然后使用 reverse_each
在给定块时产生。
否则,我们将打印它。
class Range
def todown
reverse_each do |v|
yield v if block_given?
print v unless block_given?
end
end
end
你有没有尝试过类似的东西:
(3..5).reverse_each { |i| print "hi#{i} " }
您还可以通过以下方式修补 Range:
class Range
def todown
reverse_each do |i|
if block_given?
yield i
else
print i
end
end
end
end
这样你就可以做到:
(3..5).todown { |i| print "hi#{i} " }
编辑:
我知道这个问题只是一个练习,但是在修改 Ruby 的核心 classes 时应该非常小心。 Here 是讨论 "money-patching" 的危险以及可将风险降至最低或在核心 class 补丁爆炸时使调试更容易的步骤的众多文章之一。
我们现在有一个(有点争议的)替代方案,叫做 "Refinements"。 Refinements 是对 v2.0 的实验性补充。然后在 v2.1 中对其进行了修改并永久保留。这是它在这里的工作方式。
首先,我们refine
一个模块中的class:
module M
refine Range do
def todown
reverse_each do |i|
case block_given?
when true then yield(i)
else print i
end
end
puts
end
end
end
让我们试试看:
(2...7).todown
#-> NoMethodError: undefined method `todown' for 2...7:Range
糟糕!我们已经创建了优化,但还没有激活它。为此,我们使用关键字 using
:
using M
(2...7).todown
#-> 65432
(3..5).todown { |i| print "hi#{i} " }
#-> hi5 hi4 hi3
我在细化中添加了方法,但您可以添加、修改、重命名或删除现有实例或 class 方法,添加常量等。
最后一件事:改进似乎在 IRB 中不起作用。 :tidE]
你可以这样做:
class Range
def todown
f,l = first,last
l -= 1 if exclude_end?
if block_given?
while l >= f
yield(l)
l -= 1
end
else
s = ''
while l >= f
s << l.to_s
l -= 1
end
puts(s)
end
end
end
(2...7).todown
#-> 65432
(3..5).todown { |i| print "hi#{i} " }
#-> hi5 hi4 hi3
虽然有点长,但您会看到大多数 Ruby 的内置方法(用 Ruby 编写,而不是用 C 编写)都是以类似的方式构造的,尽可能减少对其他 classes.
方法的依赖