如何在Ruby中正确链接自定义方法?
我正在尝试为以下两种方法执行链接方法。 运行此代码后,我不断获得以下输出:
#%
我的问题是:在Ruby
中链接方法的正确方法是什么?
这是我的代码:
class SimpleMath def add(a,b=0) a + b return self end def subtract(a,b=0) a - b return self end end newNumber = SimpleMath.new() print newNumber.add(2,3).add(2)
你想做这样的事吗?
class SimpleMath def initialize @result = 0 end #1 add function def add(val) @result += val self end #2 Subtract function def subtract(val) @result -= val self end def to_s @result end end newNumber = SimpleMath.new p newNumber.add(2).add(2).subtract(1)
对于任何数量的论点
class SimpleMath def initialize @result = 0 end #1 add function def add(*val) @result += val.inject(&:+) self end #2 Subtract function def subtract(*val) @result -= val.inject(&:+) self end def to_s @result end end newNumber = SimpleMath.new p newNumber.add(1, 1).add(1, 1, 1, 1).subtract(1)
让我们定义一个SimpleMath
类的实例:
sm = SimpleMath.new #=> #
这里要注意三件事:
-
sm
是一个变量。 在Ruby中,变量由小写字母表示,可选地用下划线分隔(例如,my_var
)。 - 虽然可以在
new
之后添加()
,当new
没有参数(也就是“参数”)时,这是可选的,通常不会。 - 如果关键字
return
不存在,Ruby返回该方法执行的最后一次计算。 在这里,您通常会将最后一行写为self
,并且会返回。 唉,重要的是,无论有没有关键字return
,返回self
都不是你想要的。
在IRB中尝试以下内容:
sm.add(2) #=> #
毫无疑问,你期望它返回2+0 #=> 2
,但它返回self
,正如你在上面看到的那样,实际上是sm
( #
)。
您只需删除该行即可解决此问题:
return self
从subtract
:
class SimpleMath def add(a,b=0) a + b end def subtract(a,b=0) a - b end end
现在
sm = SimpleMath.new sm.add(2) #=> 2
但是,如果我们尝试链接另一个add
,我们还有另一个问题:
sm.add(2).add(2,3) #=> NoMethodError: undefined method `add' for 2:Fixnum
这条消息非常清楚:类Fixnum
,其中2
是一个实例,没有名为add
实例方法。 那是因为你为SimpleMath
类定义了它,而不是为Fixnum
定义它。
当Ruby执行sm.add(2).add(3,4)
,它首先计算sm.add(2) #=> 2
,这将表达式减少到2.add(3,4)
。 然后它尝试将方法add
(带有两个参数)发送到2
,但是找到类2.class #=> Fixnum
没有实例方法add
; 因此例外。
我们可以通过为类Fixnum
定义这些方法来纠正该错误:
class Fixnum def add(a,b=0) a + b end def subtract(a,b=0) a - b end end
您可以通过运行以下命令确认已将这些方法添加到Fixnum
类:
Fixnum.instance_methods.sort
现在,另一个问题:
sm = Fixnum.new #=> NoMethodError: undefined method `new' for Fixnum:Class
哦,我的,类Fixnum
没有new
方法! 那是因为Fixnum
的实例是整数,无法创建。 您可以轻松确认整数是Fixnum
实例:
72.class #=> Fixnum -3.class #=> Fixnum
因此我们可以通过将add
方法发送到任何 Fixnum
实例来调用add
方法:
72.add(2) #=> 2 -3.add(2) #=> 2
现在让我们尝试链接add
操作:
72.add(2).add(3,4) #=> 7 72.add(2000000).add(3,4) #=> 7
没有例外,但没有链接。 解决此问题的方法是再次更改方法:
class Fixnum def add(b=0) puts "in add, self = #{self}, b = #{b}" self + b end def subtract(b=0) puts "in subtract, self = #{self}, b = #{b}" self - b end end
我已经在每个方法中添加了一个puts
语句,以防需要更多调试。 当代码正常工作时,我们将删除它们。 我们来测试一下:
2.add(3) #=> 5 in add, self = 2, b = 3 5.add #=> 5 in add, self = 5, b = 0 5.add(7) #=> 12 in add, self = 5, b = 7 2.add(3).add.add(7) #=> 12 in add, self = 2, b = 3 in add, self = 5, b = 0 in add, self = 5, b = 7 2.subtract(5) #=> -3 in subtract, self = 2, b = 5 -3.subtract #=> -3 in subtract, self = -3, b = 0 2.subtract(5).subtract #=> -3 in subtract, self = 2, b = 5 in subtract, self = -3, b = 0 2.add(3).subtract(5).add(7) #=> 7 in add, self = 2, b = 3 in subtract, self = 5, b = 5 in add, self = 0, b = 7
成功! 得到它?
这个家伙( tjackiw.tumblr.com )使用这个作为面试问题,并提供了一个非常干净的解决方案,了解正确答案与以下内容类似的原因和原因:
class Interpreter def initialize(&block) instance_eval(&block) end def at(time) @time = time self end def when(date) @date = date self end def we(*people) @people = people self end def going(where) @where = where self end def output [@people.join(' and '), "are going", @where, @date, "at", @time].join(' ') end end
另一种方法是通过chainable_methods gem构建管道。
文章中描述
require 'chainable_methods' module SimpleMath include ChainableMethods def add(a, b=0) a + b end def subtract(a, b=0) a - b end end SimpleMath. chain_from(5). add(5). add(5). subtract(3). unwrap