バリケンのRuby日記 RSSフィード

2006-05-22

[] 図解「String#+」メソッドの動作  図解「String#+」メソッドの動作 - バリケンのRuby日記 を含むブックマーク はてなブックマーク -  図解「String#+」メソッドの動作 - バリケンのRuby日記  図解「String#+」メソッドの動作 - バリケンのRuby日記 のブックマークコメント

こちらの動作を図解で追ってみるよ!

irb(main):001:0> a="aaa"
=> "aaa"
irb(main):002:0> b=a
=> "aaa"
irb(main):003:0> a=a+"bbb"
=> "aaabbb"
irb(main):004:0> b
=> "aaa"
irb(main):005:0> puts b
aaa
=> nil

じゃあ、最初の行から。

irb(main):001:0> a="aaa"
=> "aaa"

次のようなイメージになるよ。

f:id:muscovyduck:20060522092412p:image

次の行は、

irb(main):002:0> b=a
=> "aaa"

こんなイメージだね。

f:id:muscovyduck:20060522092408p:image

さて、問題の次の行。

irb(main):003:0> a=a+"bbb"
=> "aaabbb"

ここは、「String#+」メソッドの動作を理解する必要があるよ。a=a+"bbb"というのは、a=a.+("bbb")と書いたのと同じことになるんだよ。つまり、

  1. Stringクラスオブジェクトである"aaa"に対して、
  2. "bbb"というリテラル引数として、
  3. 「+」というメソッドを実行すると、
  4. その結果オブジェクトが生成され、(つまり"aaabbb")
  5. そのオブジェクトにaというラベルを(先ほどのオブジェクトからはがして)貼り付ける

という動作をしているよ。その結果は、次のようなイメージになるよ。

f:id:muscovyduck:20060522092407p:image

だから、次のような結果になるんだよ。

irb(main):004:0> b
=> "aaa"

irb(main):005:0> puts b
aaa
=> nil

ついでにaの内容も見てみると、次のようになるよ。

irb(main):006:0> a
=> "aaabbb"
irb(main):007:0> puts a
aaabbb
=> nil

あと、すべてのラベルがはがされたオブジェクトは、自動的にメモリ上から削除されるよ(ガーベージコレクションって言うんだって)。

上記の例だと、(図には描かなかったけど)実は"bbb"というオブジェクトが一瞬だけ生成されているんだけど、ラベルを貼っていないからすぐに消えてしまったんだよ。

[] Rubyの「破壊的メソッド」  Rubyの「破壊的メソッド」 - バリケンのRuby日記 を含むブックマーク はてなブックマーク -  Rubyの「破壊的メソッド」 - バリケンのRuby日記  Rubyの「破壊的メソッド」 - バリケンのRuby日記 のブックマークコメント

Rubyインスタンスメソッドのうち、オブジェクト自身の内容を変えてしまうようなものを「破壊的メソッド」と呼ぶよ。多くの破壊的メソッドには、メソッド名の最後に「!」が付いているよ。

例として、破壊的じゃない「String#chop」と、破壊的な「String#chop!」の違いを図解で追ってみるよ。まずは破壊的じゃないメソッド「String#chop」の例だよ。

a = "abc"
b = a.chop
puts a
puts b

まずは、最初の行。

a = "abc"

こういうイメージだね。

f:id:muscovyduck:20060522114055p:image

そして、問題の次の行。

b = a.chop

これは、次のような動作をしているよ。

  1. Stringクラスオブジェクトである"abc"に対して、
  2. chop」というメソッドの実行を依頼すると、
  3. その結果オブジェクトが生成され、(つまり"ab")
  4. そのオブジェクトにbというラベルを貼り付ける

その結果のイメージは、次のようになるよ。

f:id:muscovyduck:20060522114053p:image

だから、このスクリプトの実行結果は次のようになるんだね。

abc
ab

次は、破壊的なメソッド「String#chop!」の例だよ。

a = "abc"
b = a.chop!
puts a
puts b

最初の行は、さっきと同じだよね。

a = "abc"

こういうイメージだね。

f:id:muscovyduck:20060522114055p:image

そして、いよいよ次の行。

b = a.chop!

これは、次のような動作をしているよ。

  1. Stringクラスオブジェクトである"abc"に対して、
  2. chop!」というメソッドの実行を依頼すると、
  3. その結果オブジェクト自身が破壊され、("ab"に変化した!)
  4. そのオブジェクトにbというラベルも貼り付ける

その結果のイメージは、次のようになるよ。

f:id:muscovyduck:20060522114054p:image

なので、このスクリプトの実行結果は、次のようになるよ。

ab
ab

[] オブジェクトクラスについて  オブジェクトとクラスについて - バリケンのRuby日記 を含むブックマーク はてなブックマーク -  オブジェクトとクラスについて - バリケンのRuby日記  オブジェクトとクラスについて - バリケンのRuby日記 のブックマークコメント

Rubyオブジェクトは、必ず何らかの「クラス」から生成されているよ。そのオブジェクトの生成元のクラスを「所属クラス」と呼ぶよ。

そして一度生成されたオブジェクトは、消滅するまで所属する「クラス」が変わることはないよ。

たとえば文字列(Stringクラス)として生成されたオブジェクトは、消滅するまで所属クラスStringクラスから変わることはないよ。String#to_iを使って

a = '100'
a = a.to_i

と書いた場合、aがStringクラスからFixnumクラスに変化したように見えるかもしれないけど、実は

  1. Stringクラスオブジェクトである"100"に対して、
  2. to_i」というメソッドの実行を依頼すると、
  3. その結果Fixnumクラスオブジェクトが生成され、(つまり100)
  4. そのオブジェクトにaというラベルを貼り付ける("100"に貼られていたラベルを張り替える)
  5. ラベルをはがされた"100"は、ガーベージコレクションによってメモリから消滅する

という動作をしているよ。

イメージとしては、次のようになるよ。

a = '100'

f:id:muscovyduck:20060522144328p:image

a = a.to_i

f:id:muscovyduck:20060522144327p:image

あと、Stringクラスから生成されたオブジェクトのことを「Stringクラスインスタンス」と呼ぶみたいだよ。「インスタンスとは、オブジェクトのこと」という理解で、たぶん大丈夫だと思うよ。

メソッドの戻り値として生成されたオブジェクトや、リテラルとしてオブジェクトを生成した場合、生成元のクラス名がわからないときがあるよね。そういうときは、Object#classメソッドで調べることが出来るよ。たとえば次のように書くと、

a = 'Hello, world!'
puts a.class
a = 123
puts a.class
a = [ 1, 2, 3 ]
puts a.class
a = /abc123/
puts a.class
a = { 'a' => 1, 'b' => 2, 'c' => 3 }
puts a.class
a = :helloworld
puts a.class
a = a.class
puts a.class

実行結果は次のようになるよ。

String
Fixnum
Array
Regexp
Hash
Symbol
Class