hash ruby 定义 嵌套_ruby中的链式访问和方法嵌套

先看一道题,这道题是codewars上的一道题,我很早就看到了,但是不会写。等到又看到这道题的时候,我刚看完元编程那本书,觉得是可以搞定它的时候了。废话不多说,先看这道题,题目最开始是为JavaScript写的,但是也放在了ruby语言里面,这个没有关系。题目内容是有一个类Calc,通过链式方法调用,可以实现加减乘除。如图给的四个例子。数字只有0-9,运算只有加减乘除,而且每个运算只有一个操作符。(可以先不看下面,自己先想一下怎么写)

首先,每一个例子都是同样的结构---类名和四个方法。拿第一个例子来举例,ruby中调用一般都是 对象.方法的形式。那么初步的思路就是Calc类构建一个new方法(当然调用new的时候会自动调用initialize方法,如果只是返回一个实例对象,不用写这个方法),为Calc.new对象构建一个one方法,为Calc.new.one对象构建一个plus方法,为Calc.new.one.plus对象构建一个two方法。

这样用单例方法好像没有什么问题,虽然可能会复杂一些,但是应该是能做出来的。那怎么写呢?(其实我也不知道,要是有思路求指教)

我的思路是类似下面的,请看代码

1 classA2 defone3 defself.plus4 defself.one5 p "one+plus+one"

6 end7 self8 end9 self10 end11 end

现在的问题就是把方法名用变量来代替,但是这样的话参数怎么传进去呢?这就是个问题了。于是这种想法就搁浅了。

关于方法嵌套定义的问题,参见http://blog.csdn.net/kiwi_coder/article/details/8122085,讲的很清楚。

一种方法不通就是另一种方法了。在上一种方法中,由于我忘记返回值为self。因此经常出现nil没有方法的错误。于是就想到了method_missing。ruby中的method_missing就是在这个对象没有某个方法的时候,会到method_missing中去找解决方案。method_missing方法正好是把方法名当成参数,于是就可以直接调用了。

代码如下:

1 classCalc2 #Implement here

3@@str=""

4@@time =05defmethod_missing(name)6has = { :one => 1,:two=>2,:three => 3,:four=>4,:five => 5,7:six=>6,:seven => 7,:eight=>8,:nine => 9,:zero=>0,}8

9mth ={:plus=>"+",:minus=>"-",:times=>"*",:divided_by=>"/"}10@@str = "" if @@time == 3

11@@str << has[name].to_s ifhas.has_key?(name)12@@str << mth[name] ifmth.has_key?(name)13@@time += 1

14@@time -= 3 if @@time > 3

15if @@time == 3

16eval @@str17else

18self19end20end21 end

把方法名传入method_missing的时候,先定义两个hash,然后把方法名对应的值写到一个类变量字符串@@str中,最后用eval执行字符串。@@time是用来计算方法个数,每进行一个运算,字符串清空。值得注意的是:如果不执行的时候,要返回self。

这段代码是我提交的代码,仅仅是完成了功能,但是写的不好。

不足之处:

1使用了eval,这个方法是各种书中不推荐的

2其实两个hash可以合并,这个问题不大。

3我的这个方法只是把方法名合并成字符串,有点投机取巧,而且不能适合更多的运算。

提交之后,看了别人的代码。拿出一个推荐最多的和大家分享。

代码如下:

1 #Chainable:

2 #Calc.new.one.plus.one.plus.one == 3

3

4 classFixnum5 def plus; Calc.new("+", self) end6 def minus; Calc.new("-", self) end7 def times; Calc.new("*", self) end8 def divided_by; Calc.new("/", self) end9 end10

11 classCalc12 def initialize(*arguments)13 if arguments.length == 2

14 @operation =arguments[0]15 @number = arguments[1]16 end17 end18

19 %w(zero one two three four five six seven eight nine).each_with_index do |w,i|

20 define_method(w) { perform i }21 end22

23 defperform number24 if@operation25 @number.send(@operation, number)26 else

27 number28 end29 end30 end

简单分析一下,4-9行在Fixnum类中定义了加减乘除,并且返回Calc的对象,带着两个参数。12-17行是初始化过程。19-21行定义了0-9的对应方法,每个方法内容都是执行perform方法。23-29行定义了perform方法。拿Calc.new.one.plus.two来解释,Calc.new,不带参数,所以返回Calc的一个实例对象。Calc.new.one,调用实例方法one,

执行perform 1,此时@operation没有值,因此返回number的值1。Calc.new.one.plus,1是Fixnum类的实例,调用plus方法,返回了一个Calc.new的对象,并且带有两个参数。因此给@operation和@number分别赋值为'+',1(这里的self就是1)。Calc.new对象又调用two方法,此时有了@operation,因此执行if条件语句里的内容,得到结果3。

这种方法还可以执行更长的方法,例如Calc.new.one.plus.two.minus.three。

总结一下:链式访问要把每一个方法的对象都弄清楚,每一个方法的返回值是下一个方法的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值