2010年12月23日

[ruby-list:47706] Re: Array#values_at behavior

いまいです。

遅くなってすいません。

From: Kouya <kouyataifu4_at_gmail.com>
Date: Wed, 15 Dec 2010 23:21:22 +0900

> kouya です。

>
> array.c の value_at の実装をなんとなくみる限りでは、
> Rangeオブジェクトが渡された場合にのみ、
> 範囲チェック関数rb_range_beg_lenを呼び出して、
> begin が範囲外の場合はQnilを返し、次のセレクタの処理に移るといったように見えました。
> ので、意図した動作(仕様?)なのだと思います。
>
> // argc は selector の数
> for (i=0; i<argc; i++) {
>   // argv[i] は i番目のselector
> if (FIXNUM_P(argv[i])) {
> rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
>    // selector がfixnum の場合は一つずつ要素を配列につっこむ。
> continue;
> }
> /* check if idx is Range */
> switch (rb_range_beg_len(argv[i], &beg, &len, olen, 0)) {
> // rb_range_beg_len は beginが範囲内にないと Qnil をかえす。たぶん。
> case Qfalse:
> break;
> case Qnil:
> continue;
> default:
> for (j=0; j<len; j++) {
> rb_ary_push(result, (*func)(obj, j+beg));
> }
> continue;
> }
>   // continue するので、ここには到達しない。begin が範囲外の場合は無視されている。
> rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
> }

ありがとうございます。Qfalse/Qnil の辺りの理解があやふやですが、おおむ
ね理解出来ました。

> なお、ソースコードの使用例にもセレクターに二つ以上のRangeオブジェクトが指定できると書いてありました。
>
> $ ruby-19-trunk -ve 'p [1,2,3].values_at(-4..3, 1..2, 0..10)'
> ruby 1.9.3dev (2010-11-07 trunk 29711) [x86_64-darwin10.4.3]
> [2, 3, 1, 2, 3, nil]

* -4..3 #=> begin が範囲外なので無視
* 1..2 #=> 前半の [2, 3]
* 0..10 #=> 後半の [1, 2, 3, nil]

という対応ですね。

> ですので、説明を書くならば、
> 「セレクターにRange オブジェクトを渡した場合、begin が範囲外の場合はその範囲は無視されます。
> end が範囲外ならば、nil が代入され、それ以降の範囲は無視します。」
> といったかんじでしょうか。

2文目は、

「Range の途中で配列の範囲外になると nil を代入?して、それ以降の範囲は
無視します。」

でしょうか。上の例で言うと、0..10 という Range のうち、0、1、2、までは
配列の範囲内、3の時点で範囲外になるのでnil、4から10までは無視、という
感じです。
# rb_range_beg_len は、その辺を考慮した「長さ」をlenにセットするんです
# ね。たぶん。
--
Nobuhiro IMAI <nov@xxxxx>
Key fingerprint = E57F 2482 4074 13BC 3B9A 165B C689 5B16 A620 4657


投稿者 xml-rpc : 2010年12月23日 14:29
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/100915
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。