ログイン
編集不可のページディスカッション情報添付ファイル
"alstamber/2013FreshmanRubySeminar5"の差分

MMA
5と8のリビジョン間の差分 (その間の編集: 3回)
2013-06-07 17:10:08時点のリビジョン5
サイズ: 2444
編集者: alstamber
コメント:
2013-06-12 13:47:38時点のリビジョン8
サイズ: 11206
編集者: alstamber
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 45: 行 45:
def Hoge class Hoge
行 54: 行 54:
クラスメソッドは次のようにしても定義できます。

{{{#!highlight ruby
class Hoge
    class << Hoge
        def f
            (処理)
        end
    end
end
}}}

この定義の仕方についてより詳しく知りたい人は「特異クラス」でググってください。
行 55: 行 69:
今までクラスは特にお互い関係なく別個に存在するものとして扱ってきました。しかし現実は違います。<<BR>>
ここではクラス同士がお互いにどのような関係を持っているのかについて見ていきましょう。

実はクラス同士には親子関係といえるような関係が存在します。親子というのはどういうことでしょうか。

クラスAとクラスBがあったとします。この2つに親子関係があるとします。<<BR>>
親子関係があるということは片方が親で、もう片方が子ということになります。ここではクラスAが親で、クラスBが子であるとします。<<BR>>
親の立場にあるクラスをスーパークラスといいます。子の立場にあるクラスをサブクラスといいます。

クラスが親子関係にあると、次のようなことがいえるようになります。
{{{
スーパークラスにあるインスタンスメソッドが全てサブクラスでもつかえるようになる
}}}

実際にクラスAとクラスBにメソッドを定義して詳しくみていくことにしましょう。

{{{#!highlight ruby
#このプログラムはこのままではこれから説明するような動きをしない(AとBの間に親子関係があるということを書いていないから)
class A
    def f
        puts "akari"
    end
end

class B
    def g
        puts "kyoko"
    end
end
}}}

この状態で次のプログラムを実行するとどうなるかを考えます。

{{{#!highlight ruby
a = A.new
b = B.new

a.f
a.g
b.f
b.g
}}}

まずa.fについて考えます。クラスAにはメソッドfが定義されているので、それが実行されakariと出力されます。<<BR>>
次にa.gについて考えます。クラスBにはメソッドgは定義されていないので、エラーになります。

さらにb.fについて考えます。クラスBにはメソッドfは定義されていませんが、クラスBのスーパークラスであるクラスAにはメソッドfが定義されています。<<BR>>
なのでそちらが実行されて、akariが出力されます。<<BR>>
最後にb.gについて考えます。クラスBにはメソッドgが定義されているので、kyokoが出力されます。

=== オーバーライド ===
さて次のような疑問が湧いてきた人がいるかもしれません。

{{{
サブクラスとスーパークラスに同じ名前のメソッドがあったらどっちが実行されるの?
}}}

答えは、サブクラスのものが優先される、です。<<BR>>
スーパークラスに既にメソッドが定義されていても、それと同じ名前のメソッドを定義すれば、その内容を上書きできるわけです。<<BR>>
これを上書きという意味の英語を使ってメソッドのオーバーライドといいます。

=== クラスの親子関係の例 ===
クラスの親子関係の例としてみんな大好きなStringクラスを使いましょう。<<BR>>
StringクラスにはスーパークラスとしてComparableクラスというものがあります。<<BR>>
Comparableクラスは比較可能なオブジェクトを表すクラスです。<<BR>>
例えば==という名前のメソッドが定義されています。これは二つのComparableクラスのオブジェクトが等しいかどうかを判定するメソッドです。

StringクラスはComparableクラスのサブクラスなので、この==メソッドを使うことができます。<<BR>>
{{{#!highlight ruby
"hoge" == "fuga"
}}}
のような文字列が等しいかどうかを判定する処理は、内部的にStringクラスの==メソッドを呼びだす処理に書きかえられています。<<BR>>
気持ちとしてはこんな感じ。
{{{#!highlight ruby
"hoge".==("fuga")
}}}
Stringクラスそのものには==メソッドはないですが、StringクラスのスーパークラスになっているComparableクラスには==メソッドが定義されているので、<<BR>>
めでたく比較をすることができる、というわけです。

Comparableクラスは他にも沢山のサブクラスを持っています。小数を表すクラスであるFloatクラスもそのひとつです。<<BR>>
2つのオブジェクトを比較するという処理を一つのクラスにまとめることで、FloatクラスやStringクラスに別々に何度も比較する処理を書かなくてよいので楽ができるというわけですね。
行 57: 行 152:
クラスの親子関係は皆さんがコンピュータリテラシーで学んだであろうディレクトリ構造にも似ています。<<BR>>
ディレクトリにも親のディレクトリと子のディレクトリがありましたね。たとえばfooというディレクトリの中にbarというディレクトリが入っていれば<<BR>>
fooが親ディレクトリであり、barが子ディレクトリということになります。

ディレクトリの親子関係は何代にもつなげることができます。あるディレクトリに対してその親の親の親、のようなものも考えることができるわけです。<<BR>>
クラスでも同じようにあるクラスに対してその親のさらに親を考えることができます。たとえばFloatクラスは親がNumericクラスで、更にその親がComparableクラスになっています。<<BR>>
先ほどComparableクラスはFloatクラスをサブクラスに持っていると言いましたが、正確には子供の子供、なわけですね。しかし子供の子供も結局間接的には自分の子供なので、サブクラスといってしまっていいわけです。

ディレクトリと同じようにあるクラスは子供はたくさん持てますが、親はひとつしか持てません。<<BR>>

またディレクトリ構造で言うところのルートディレクトリにあたるものが存在するのではないかという気がしてきますね。実際それは存在していて、Objectクラスと呼ばれています。

=== Objectクラスの性質 ===
Objectクラスにはto_sというメソッドが用意されています。Objectクラスはすべてのクラスのスーパークラスなので、Rubyのすべてのオブジェクトはto_sメソッドを持っていることになります。<<BR>>
つまりどんなオブジェクトでも文字列を使った表現に変換することができます。putsメソッドを使ってオブジェクトの内容を表示できるのはこのおかげなのです。

putsメソッドもここに定義されています。

=== mainオブジェクト(暇な人向け) ===
実はRubyではプログラム全体がひとつのオブジェクトになっています。これをmainオブジェクトと言います。Rubyのプログラムにクラスなどを挟まずに直接メソッドをベタ書きすると<<BR>>
mainオブジェクトのメソッドになります。mainオブジェクトはObjectクラスのインスタンスです。

=== self(暇な人向け) ===
selfという特別なキーワードがあります。これは場所によって様々な意味を持ちます。
{{{
クラスの定義の直下……そのクラスそのもの
クラスの中のインスタンスメソッドの定義の中……インスタンスそのもの
}}}

これを使うとクラスメソッドの定義を次のように書き直せます。

{{{#!highlight ruby
class Hoge
    class << self
         def f
              (処理)
         end
    end
end
}}}

クラスの定義を挟まず、Rubyのプログラムに直接selfを使うとどういう意味になるのでしょうか。先ほどRubyのプログラムは全体でmainオブジェクトというObjectクラスのインスタンスになっているのだという話をしました。<<BR>>
なので、この場合selfはmainオブジェクトを意味することになります。

selfは「.」の前につけて使うときは省略できます。実は今まで使ってきたputsメソッドは
{{{#!highlight ruby
self.puts "hogehoge"
}}}
の省略形だったということです。

クラスもオブジェクト

クラスはオブジェクトを作るための設計図だという話をしました。
ここで驚くべき話があります。実はRubyではクラスもまたオブジェクトなのです!!!!!

RubyではクラスはClassというクラスのインスタンスになっています。

となると当然疑問が湧いてきます。Classというクラスはどのクラスからつくられているの?という疑問です。
答えを正確に説明するのは難しいのですが、ここではClassというクラスのインスタンスは自分自身から作られている、という説明にとどめておきます。

クラスインスタンス変数

クラスもやっぱりオブジェクトなので、今までみてきたオブジェクトと同じように変数を持ったりメソッドを持ったりできます。
最初に、クラス自体のインスタンスが持っている変数についてみていくことにしましょう。

クラス自体のインスタンスが持っている変数をクラスインスタンス変数といいます。そのまんまですね。

クラスインスタンス変数の作りかた

クラスインスタンス変数を作るには次のようにします。

   1 class Hoge
   2     @a = (初期値)
   3 end

ただのインスタンス変数となにが違うのかみてみましょう。

   1 class Hoge
   2     @a = (初期値)
   3 
   4     def f
   5         @b = (初期値)
   6     end
   7 end

インスタンスメソッドの中で定義されるとインスタンス変数になり、外で定義されるとクラスインスタンス変数になります。

クラスメソッド

次はメソッドの話です。クラスも通常のオブジェクトと同じようにメソッドを持つことができます。
このようなメソッドをクラスが持っているメソッドなのでクラスメソッドといいます。

クラスメソッドの定義

クラスメソッドは次のように定義します。

   1 class Hoge
   2     def Hoge.f
   3         (処理)
   4     end
   5 end

メソッド名の頭にクラス名を書けばよいことがわかりますね。

クラスメソッドは次のようにしても定義できます。

   1 class Hoge
   2     class << Hoge
   3         def f
   4             (処理)
   5         end
   6     end
   7 end

この定義の仕方についてより詳しく知りたい人は「特異クラス」でググってください。

クラスには親子関係がある

今までクラスは特にお互い関係なく別個に存在するものとして扱ってきました。しかし現実は違います。
ここではクラス同士がお互いにどのような関係を持っているのかについて見ていきましょう。

実はクラス同士には親子関係といえるような関係が存在します。親子というのはどういうことでしょうか。

クラスAとクラスBがあったとします。この2つに親子関係があるとします。
親子関係があるということは片方が親で、もう片方が子ということになります。ここではクラスAが親で、クラスBが子であるとします。
親の立場にあるクラスをスーパークラスといいます。子の立場にあるクラスをサブクラスといいます。

クラスが親子関係にあると、次のようなことがいえるようになります。

スーパークラスにあるインスタンスメソッドが全てサブクラスでもつかえるようになる

実際にクラスAとクラスBにメソッドを定義して詳しくみていくことにしましょう。

   1 #このプログラムはこのままではこれから説明するような動きをしない(AとBの間に親子関係があるということを書いていないから)
   2 class A
   3     def f
   4         puts "akari"
   5     end
   6 end
   7 
   8 class B
   9     def g
  10         puts "kyoko"
  11     end
  12 end

この状態で次のプログラムを実行するとどうなるかを考えます。

   1 a = A.new
   2 b = B.new
   3 
   4 a.f
   5 a.g
   6 b.f
   7 b.g

まずa.fについて考えます。クラスAにはメソッドfが定義されているので、それが実行されakariと出力されます。
次にa.gについて考えます。クラスBにはメソッドgは定義されていないので、エラーになります。

さらにb.fについて考えます。クラスBにはメソッドfは定義されていませんが、クラスBのスーパークラスであるクラスAにはメソッドfが定義されています。
なのでそちらが実行されて、akariが出力されます。
最後にb.gについて考えます。クラスBにはメソッドgが定義されているので、kyokoが出力されます。

オーバーライド

さて次のような疑問が湧いてきた人がいるかもしれません。

サブクラスとスーパークラスに同じ名前のメソッドがあったらどっちが実行されるの?

答えは、サブクラスのものが優先される、です。
スーパークラスに既にメソッドが定義されていても、それと同じ名前のメソッドを定義すれば、その内容を上書きできるわけです。
これを上書きという意味の英語を使ってメソッドのオーバーライドといいます。

クラスの親子関係の例

クラスの親子関係の例としてみんな大好きなStringクラスを使いましょう。
StringクラスにはスーパークラスとしてComparableクラスというものがあります。
Comparableクラスは比較可能なオブジェクトを表すクラスです。
例えば==という名前のメソッドが定義されています。これは二つのComparableクラスのオブジェクトが等しいかどうかを判定するメソッドです。

StringクラスはComparableクラスのサブクラスなので、この==メソッドを使うことができます。

   1 "hoge" == "fuga"

のような文字列が等しいかどうかを判定する処理は、内部的にStringクラスの==メソッドを呼びだす処理に書きかえられています。
気持ちとしてはこんな感じ。

   1 "hoge".==("fuga")

Stringクラスそのものには==メソッドはないですが、StringクラスのスーパークラスになっているComparableクラスには==メソッドが定義されているので、
めでたく比較をすることができる、というわけです。

Comparableクラスは他にも沢山のサブクラスを持っています。小数を表すクラスであるFloatクラスもそのひとつです。
2つのオブジェクトを比較するという処理を一つのクラスにまとめることで、FloatクラスやStringクラスに別々に何度も比較する処理を書かなくてよいので楽ができるというわけですね。

Objectクラス

クラスの親子関係は皆さんがコンピュータリテラシーで学んだであろうディレクトリ構造にも似ています。
ディレクトリにも親のディレクトリと子のディレクトリがありましたね。たとえばfooというディレクトリの中にbarというディレクトリが入っていれば
fooが親ディレクトリであり、barが子ディレクトリということになります。

ディレクトリの親子関係は何代にもつなげることができます。あるディレクトリに対してその親の親の親、のようなものも考えることができるわけです。
クラスでも同じようにあるクラスに対してその親のさらに親を考えることができます。たとえばFloatクラスは親がNumericクラスで、更にその親がComparableクラスになっています。
先ほどComparableクラスはFloatクラスをサブクラスに持っていると言いましたが、正確には子供の子供、なわけですね。しかし子供の子供も結局間接的には自分の子供なので、サブクラスといってしまっていいわけです。

ディレクトリと同じようにあるクラスは子供はたくさん持てますが、親はひとつしか持てません。

またディレクトリ構造で言うところのルートディレクトリにあたるものが存在するのではないかという気がしてきますね。実際それは存在していて、Objectクラスと呼ばれています。

Objectクラスの性質

Objectクラスにはto_sというメソッドが用意されています。Objectクラスはすべてのクラスのスーパークラスなので、Rubyのすべてのオブジェクトはto_sメソッドを持っていることになります。
つまりどんなオブジェクトでも文字列を使った表現に変換することができます。putsメソッドを使ってオブジェクトの内容を表示できるのはこのおかげなのです。

putsメソッドもここに定義されています。

mainオブジェクト(暇な人向け)

実はRubyではプログラム全体がひとつのオブジェクトになっています。これをmainオブジェクトと言います。Rubyのプログラムにクラスなどを挟まずに直接メソッドをベタ書きすると
mainオブジェクトのメソッドになります。mainオブジェクトはObjectクラスのインスタンスです。

self(暇な人向け)

selfという特別なキーワードがあります。これは場所によって様々な意味を持ちます。

クラスの定義の直下……そのクラスそのもの
クラスの中のインスタンスメソッドの定義の中……インスタンスそのもの

これを使うとクラスメソッドの定義を次のように書き直せます。

   1 class Hoge
   2     class << self
   3          def f
   4               (処理)
   5          end
   6     end
   7 end

クラスの定義を挟まず、Rubyのプログラムに直接selfを使うとどういう意味になるのでしょうか。先ほどRubyのプログラムは全体でmainオブジェクトというObjectクラスのインスタンスになっているのだという話をしました。
なので、この場合selfはmainオブジェクトを意味することになります。

selfは「.」の前につけて使うときは省略できます。実は今まで使ってきたputsメソッドは

   1 self.puts "hogehoge"

の省略形だったということです。

alstamber/2013FreshmanRubySeminar5 (最終更新日時 2013-06-12 13:47:38 更新者 alstamber)