Re: [問題] 關於stdlib matrix

看板Ruby作者 (godfat 真常)時間13年前 (2011/12/13 01:06), 編輯推噓1(100)
留言1則, 1人參與, 最新討論串2/2 (看更多)
: 推 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

12/13 11:22, , 1F
謝謝,上了一課。
12/13 11:22, 1F
文章代碼(AID): #1EvZIWMG (Ruby)
文章代碼(AID): #1EvZIWMG (Ruby)