[ruby-list:46863] []= メソッドの第一引数を省略したい

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[ruby-list:46863] []= メソッドの第一引数を省略したい

Yuya Takeyama
こんにちは。竹山と申します。

[]= メソッドについて質問です。
PHP の、以下のような構文を Ruby で実現したいと思っています。

$arr[] = "zero";
// => array(0 => "zero");
$arr[] = "one";
// => array(0 => "zero", 1 => "one")

念のため説明すると、PHP では
$arr[] = "foo";
とすることで、配列 $arr の末尾に "foo" という要素が追加されます。

そこで、以下のようなコードを書いてみたのですが、うまくいきませんでした。
手元の Ruby のバージョンは 1.8.7 です。
(インデントに全角スペースを使っていることにご注意ください)

class MyArray < Array
 def []=(key, val)
  if key.nil?
   self.push(val)
  else
   super(key, val)
  end
 end
end

arr = MyArray.new
arr[] = "zero"
# => ArgumentError: wrong number of arguments (1 for 2)

引数にデフォルト値を与えればいいのかと思い、以下のような変更を行いましたが、
これもうまくいきませんでした。

def []=(key = nil, val)

これは Syntax Error となりました。

ちなみに、最初に書いたコードの MyArray を使って

arr[nil] = "zero"

というように書くと、末尾に要素が追加されていくのですが、
これではあまり意味が無いのは言うまでも無いと思います。

思いつきで書いてみただけなので、特に問題ではないのですが、
実現できないかと思っていますが、これは仕様上できないのでしょうか。

どなたかご返答いただければ幸いです。
以上、よろしくお願いします。

Yuya Takeyama

Reply | Threaded
Open this post in threaded view
|

[ruby-list:46864] Re: []= メソッドの第一引数を省略したい

from_kyushu
from_kyushuと申します。

On 2010/02/18, at 1:21, Yuya Takeyama wrote:

> 引数にデフォルト値を与えればいいのかと思い、以下のような変更を行いましたが、
> これもうまくいきませんでした。
>
> def []=(key = nil, val)
>
> これは Syntax Error となりました。
>

引数が2つ以上あるメソッドで、1番目の引数だけにデフォルト値を設定することは出来ません。
2番目以降にもデフォルト値を設定するか、可変長引数を使う必要があったと思います。
なのでこう書けば動きました。

--------------------
class MyArray < Array
  def []=(key,val=nil)
    if val.nil?
      self.push(key)
    else
      super(key,val)
    end
  end
end

arr = MyArray.new
arr[] = 1 # => 1
arr[] = 2 # => 2
arr # => [1, 2]
--------------------

from_kyushu
Reply | Threaded
Open this post in threaded view
|

[ruby-list:46865] Re: []= メソッドの第一引数を省略したい

Yuya Takeyama
from_kyushu さん、こんにちは。
ご返答ありがとうございます。


(2010年02月18日 03:36), from_kyushu wrote:

> 引数が2つ以上あるメソッドで、1番目の引数だけにデフォルト値を設定することは出来ません。
> 2番目以降にもデフォルト値を設定するか、可変長引数を使う必要があったと思います。
> なのでこう書けば動きました。
>
> --------------------
> class MyArray < Array
>   def []=(key,val=nil)
>     if val.nil?
>       self.push(key)
>     else
>       super(key,val)
>     end
>   end
> end
>
> arr = MyArray.new
> arr[] = 1 # => 1
> arr[] = 2 # => 2
> arr # => [1, 2]
> --------------------
>
> from_kyushu
>  

なるほど!そういうことだったんですね。
オライリーの本で、確かにそういったことを読んだ覚えはありますが、
いざ書いてみると、自分の理解がまだまだなことを思い知らされますね・・・。

ですが、

>     if val.nil?
>       self.push(key)
>     else

ここの部分はちょっと不思議ですね。
てっきり key.nil? を見るべきだと思っていたので。
このような仕様にした意図が気になるところです。

軽い気持ちで質問したつもりが、思った以上に深かったようで、
これからの参考になりそうです。

どうもありがとうございました。

Yuya Takeyama


Reply | Threaded
Open this post in threaded view
|

[ruby-list:46866] Re: []= メソッドの第一引数を省略したい

西 啓一朗
ちょっとだけツッコミ

>   def []=(key,val=nil)
>     if val.nil?
>       self.push(key)
>     else
>       super(key,val)
>     end
>   end
> end

これだと、

> arr = MyArray.new
> arr[] = 1 # => 1
> arr[] = 2 # => 2
> arr # => [1, 2]

arr[0] = nil # => 0
arr #=> [1, 2, 0]

と意図しない動作になると思います。
デフォルト値ではなく可変長引数を使って

def []=(key, *val)
  if val.empty?
    self.push key
  else
    super(key, *val)
  end
end

とした方が良いと思います。

> ここの部分はちょっと不思議ですね。
> てっきり key.nil? を見るべきだと思っていたので。
> このような仕様にした意図が気になるところです。

メソッドの呼び出しに置き換えてみればわかりやすいかと。
値が省略されるというのは文字通り「何も書かない」以外では表記できません。

arr[3] = "test" # => arr.[]=(3, "test")
arr[nil] = 12 #=> arr.[]=(nil, "test")
arr[] = 5 #=> arr.[]=(5)

--
西 啓一朗 <[hidden email]>