两道测试题
看到两道关于 proc
的测试题,挺有意思,做个记录。
测试题一
题目
补全以下代码,实现一个计数器的功能,每次调用 a 可以得到累加的数值。
def counter n
# ...
end
a = counter(10)
答案
def counter n
proc { n += 1 }
end
a = counter(10)
p a.call
# => 11
p a.call
# => 12
counter
方法内部定义了一个 block, a = counter(10)
其实是得到了一个 匿名函数 proc { n += 1 }
,且 变量 n
有初始值 n = 10
。用 call
调用第一次时,返回值是 n = 10 + 1
,调用第二次时,返回值是 n = 11 + 1
,以此类推。
测试题二
题目
实现以下类 EnuTest 的功能
enu = EnuTest.new do |x|
x << 1
x << 3
x << proc { 'hello' }
end
enu.next # => 1
enu.next # => 3
enu.next # => 'hello'
enu.next # => raise error 'EOF'
答案
class EnuTest
def initialize &block
@eb = EnuBlock.new
yield @eb
end
def next
@eb.next
end
end
class EnuBlock
def initialize
@blocks = []
end
def << obj
if obj.is_a? Proc
@blocks << obj
else
@blocks << proc { obj }
end
end
def next
if @blocks.empty?
raise 'EOF'
else
@blocks.shift.call
end
end
从题目的要求来看,EnuTest
的实例应该是一个 Array
,而这个 Array
起码要支持 integer
和 proc
这两种类型。答案的思路是,把这个 Array
的元素全部定义为 proc
,每次调用 next
方法,就会运行一个 proc
。
为了将输入的元素转成 proc
,答案还重新定义了 <<
方法,遇到非 proc
的变量,先其转成 proc
。
最后用的的 shift
方法会将 array
第一个元素删除,并同时返回被删的这个元素。