我正在尝试为以下两种方法执行链接方法。运行此代码后,我不断收到以下输出:
#<SimpleMath:0x007fc85898ab70>%
我的问题是: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)
答案 0 :(得分:12)
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)
答案 1 :(得分:6)
让我们定义您的班级SimpleMath
的实例:
sm = SimpleMath.new #=> #<SimpleMath:0x000001020ca820>
这里要注意三件事:
sm
是一个变量。在Ruby中,变量由小写字母表示,可选地用下划线分隔(例如,my_var
)。()
之后添加new
,但new
没有参数(又名&#34;参数&#34;),那就是&#39}可选的,通常不会。return
不存在,Ruby将返回该方法执行的最后一次计算。在这里,您通常会将最后一行写为self
,并且会返回。唉,重要的是,返回self
,无论有没有关键字return
,都不是你想要的。在IRB中尝试以下内容:
sm.add(2) #=> #<SimpleMath:0x000001020ca820>
毫无疑问,您希望这会返回2+0 #=> 2
,而是返回self
,正如您在上面看到的那样,sm
(#<SimpleMath:0x000001020ca820>
)
您只需删除以下行即可解决此问题:
return self
来自add
和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
实例来调用{<1}}方法:
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
成功!得到它?
答案 2 :(得分:1)
这个家伙(tjackiw.tumblr.com)使用这个作为面试问题,并提供了一个非常干净的方式,如何&amp;为什么正确的答案类似于以下内容:
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
答案 3 :(得分:1)
另一种方法是通过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