作者godfat (godfat 真常)
看板Ruby
标题Re: [问题] 关於stdlib matrix
时间Tue Dec 13 01:06:37 2011
: 推 godfat:为什麽你觉得需要修改 Fixnum..? 12/12 22
: → rexkimta:要用1*Matrix[[1,2],[3,4]]这种型式的语法,不是就应该 12/12 22
: → rexkimta:定义Fixnum*Matrix吗?不然至少也要修改Numeric? 12/12 22
ok, 因为我没用过 matrix, 所以不知道这样可以动。这种时候就是
Use the source, Tux 的时候了。首先我们先翻到 Fixnum#*
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c#L3609
rb_define_method(rb_cFixnum, "*", fix_mul, 1);
所以我们去找 fix_mul 这个 c function:
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c
#L2575-2582
这边可以看到 fix_mul 在 rhs 不是 FIXNUM_P(y) 时,会去 FIXNUM_P(y)
由於什麽都不是,最後会跑到 return rb_num_coerce_bin(x, y, '*');
接下来就看 rb_num_coerce_bin 是什麽:
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c
#L219-224
我们会看到重点是 do_coerce(&x, &y, TRUE); 接着就去看他的定义:
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c
#L198-217
在 L206 的地方,可以看到 ruby 又呼叫 coerce_body, 取得某个 array,
并把 lhs 和 rhs 分别替换成这个 coerce_body 回传的 array 的 first 和 last.
接着看 coerce_body 定义:
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c
#L179-183
这里我们看到,coerce_body 会对 rhs 呼叫 id_coerce, 再查一下 id_coerce
https://github.com/ruby/ruby/blob/900b4a6db63012d9ce32a1019a7c9d5b014a0047/
numeric.c#L3540
可以发现其实就是 :coerce, 一个 ruby 的 symbol. 也就是说,他尝试呼叫
rhs.coerce lhs
套到这里来,其实就是 Matrix[[1,2],[3,4]].coerce 1
并把其结果重新定为 lhs 和 rhs, 再套 * 上去。
测试一下:
Matrix[[1,2],[3,4]].coerce 1
会得到:
[#<Matrix::Scalar:0x000001009991d8 @value=1>, Matrix[[1, 2], [3, 4]]]
也就是说,当我们写:
1 * Matrix[[1,2],[3,4]]
时,ruby 会先看 matrix 不是 numeric, 因此呼叫 Matrix#coerce 1
把 1 改写成 scalar, 并当作新的 lhs, 再把原本的 matrix 当作 rhs.
在 matrix.rb 中,就可以找到这个 Matrix#coerce 的定义:
def coerce(other)
case other
when Numeric
return Scalar.new(other), self
else
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
end
end
因此我们可以定义一个 Two class:
class Two
def coerce lhs
[lhs, 2]
end
end
然後得到 100 * Two.new # => 200
--
By Gamers, For Gamers - from the past Interplay
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.38.235
1F:推 rexkimta:谢谢,上了一课。 12/13 11:22