class(クラス)はメソッドなどの共通処理を一つにまとめたものです。プログラミングを行う上でクラスを定義することはよくありますが、いまいち使い方をわかっていない人も多いのではないでしょうか?
クラスの使い方がよくわからない
クラスの変数や継承、モジュールってどういうこと?
そんな方にむけて、ここではRubyのclass(クラス)について網羅的に解説します。
- クラス(class)とは
- インスタンスとは
- クラスのinitialize
- クラスのメソッド
- クラスの変数
- クラスの継承
- クラスとモジュール
このページで、Rubyのclass(クラス)の使い方をよく把握して、自分のスキルとしていきましょう!
クラス(class)とは
クラス(class)とは、メソッドなどの処理を入れる入れ物のようなものです。Rubyなどのオブジェクト指向型の言語では、この入れ物であるクラスの中に処理を書くことが基本となってきます。
class User def name @name end def name=(name) @name = name end end
クラスを定義するということは、具体的にはクラスの定義よりRuby言語に新しい「型」を加えることです。その型をnewすると、変数に新しい型の「値」を代入できるようになります。
たとえば、以下のサンプルコードは、Stringクラスという「型」からnewしてString型の値を作成し、変数whoへ値を代入しています。そして、「p who」でwhoの中身の値を表示しています。
この場合は文字列の”jobs”ですね。
# Stringという型(クラス)の値をnewで作成し変数whoへ代入 who = String.new("jobs") #whoにはString型の値が入っている p who
[実行結果]
"jobs"
次のサンプルコードでは、上に記載したUserクラスの「型」からnewしてUserクラスの値を作成し、変数userに値を代入しています。
class User def name @name end def name=(name) @name = name end end # Userという型(クラス)の値をnewで作成し変数userへ代入 user = User.new #userにはUser型の値が入っている p user user.name = "user" p user.name
[実行結果]
#<User:0x4da9330> "user"
実行結果の1行目で、「p user」の出力結果が得られています。この場合、Rubyのクラスの表示方法として決められている定型フォーマットに沿った「なにがしかのクラスです」という意味の表示である「#<User:0x4da9330>」という表示になっています。
これの意味するところは「Userクラスの値ですよ」ということです。実行結果の2行目は、Userクラスのメソッドの出力です。RubyにはStringなどあらかじめ用意されている便利なクラス(型)がたくさんあります。
それに加えて、ユーザー自身がRubyに新たなクラス(型)を付け加えて、ユーザーがより良くRubyを使えるようにカスタマイズすることができます。
この点について、以降で詳しく解説していきます。
クラスとインスタンス
クラスには処理を書いていきますが、実際に処理を行うときは、クラスから「インスタンス」と呼ばれるものを生成して、処理を行わせることが多いです。インスタンスの生成には「new」メソッドを使用します。
class User def name @name end def name=(name) @name = name end end user = User.new user.name = "taro" p user.name
[実行結果]
taro
このようにクラスを使用するときは基本的に、「new」メソッドを使用してインスタンスを生成して、処理を行うという流れを意識しましょう。よく言われる例としてはクラスがたい焼きの型、インスタンスがたい焼きなどと言われます。
要はクラスからインスタンスが生成されるというイメージを持つことが大切です。また、インスタンスはそれぞれ独立して値を持つことができます。
class User def name @name end def name=(name) @name = name end end user1 = User.new user2 = User.new user1.name = "taro" user2.name = "hanako" p user1.name p user2.name
[実行結果]
taro hanako
上の例では、Userのインスタンスを作成して、それぞれにデータを持っていることが確認できます!
クラスのinitialize
Rubyのクラスのinitializeメソッドはクラスがnewされた際に一度だけ実行されるメソッドです。主にクラスの初期化を行います。
実際にコードを見てみましょう。
class Hello def initialize(username) @username = username end def hello puts "hello, " + @username.to_s end end h = Hello.new("Kevin") h.hello
[実行結果]
hello, Kevin
上のコードでは、newの引数に”Kevin”を与えて実行しています。newが呼ばれた際にHelloクラスのinitializeメソッドが呼び出され、newの引数がinitializeの引数に渡されます。
initializeでは、引数をもとにクラス変数@usernameを初期化しています。その後Helloクラスのhelloメソッドを呼び出した際に、@usernameがきちんと初期化した通り表示されていますね。
ただし、initializeは複数定義してオーバーロードできません。実際に例をみてみましょう。
class Hello def initialize(he) @he = he end def initialize(he,her) @he = he @her = her end def hello puts "hello, Mt." + @he.to_s + " and Ms." + @her.to_s end end #h = Hello.new("Kevin") #=>wrong number of arguments (given 1, expected 2) (ArgumentError) h = Hello.new("Kevin", "Jane") #=>hello, Mt.Kevin and Ms.Jane h.hello
[実行結果]
#h = Hello.new("Kevin") #=>wrong number of arguments (given 1, expected 2) (ArgumentError) hello, Mt.Kevin and Ms.Jane
Helloクラスの一番目のinitializeメソッドを使用しようとするとエラーがでますね。これは、一番目のinitializeメソッドの定義が、二番目のinitializeメソッドの定義で上書きされてしまっているからです。
そのため、一番目のinitializeメソッドの定義はもう存在せず、それを使おうとするとエラーとなります。クラスのinitializeについてはこちらにまとめられているので参考にしてください。
クラスのメソッド
クラスメソッド
クラスメソッドはクラス名をレシーバとして実行するメソッドです。クラスメソッドからは、後述するクラス変数しかアクセスできません。
クラス変数とは、クラスから作成したすべての変数(インスタンス)が共通して持っている変数です。通常、変数(インスタンス)は、値を変数ごとに別々に持っていますが、クラス変数だけは、共通して持っています。
また、クラスメソッドからは、後述するインスタンス変数にはアクセスできません。クラスメソッドはそのクラスから作成したすべての変数(インスタンス)が共通して持っているメソッドです。
そのため、別々に分かれた変数(インスタンス)が別々の値として持っているインスタンス変数は操作できません。実際にサンプルコードで確認してみましょう。
class Counter @@cnt = 0 def initialize(counter_name) @@cnt+=1 @counter_name = counter_name end def self.get_cnt @@cnt end def self.counter_name @counter_name end end cnt1 = Counter.new("apple") cnt2 = Counter.new("banana") cnt3 = Counter.new("cookie") p Counter.get_cnt p Counter.counter_name
[実行結果]
3 nil
実行結果の1行目では、クラスメソッド「Counter.get_cnt」からクラス変数@@cntにアクセスした値が表示されています。Counterをnewするたびに、initializeで「@@cnt+=1」していました。
Counterの変数(インスタンス)を3つ作成してるので、@@cntも「3」までカウントアップされています。実行結果の2行目では、クラスメソッド「Counter.couter_name」から、インスタンス変数「@counter_name」にアクセスしています。
しかし、クラスメソッドからインスタンス変数にはアクセスできないため、結果はnilとなっています。クラスメソッドについてはこちらの記事にまとめられているので参考にしてください。
インスタンスメソッド
クラスメソッドで解説したCounterクラスで、インスタンスメソッドについて解説します。今度は、「self. counter_name」というクラスメソッドから「self」を外し、「counter_name」というインスタンスメソッドに変更します。
また、「self.get_cnt」クラスメソッドも、「get_cnt」インスタンスメソッドにしましょう。違いはこれだけです。
実際にサンプルコードを見ていきましょう。
class Counter @@cnt = 0 def initialize(counter_name) @@cnt+=1 @counter_name = counter_name end def get_cnt @@cnt end def counter_name @counter_name end end cnt1 = Counter.new("apple") cnt2 = Counter.new("banana") cnt3 = Counter.new("cookie") p cnt3.get_cnt p "cnt1=" + cnt1.counter_name p "cnt2=" + cnt2.counter_name p "cnt3=" + cnt3.counter_name
[実行結果]
3 "cnt1=apple" "cnt2=banana" "cnt3=cookie"
「counter_name」をインスタンスメソッドにしただけで、インスタンス変数「@counter_name」にアクセスできています。また、「@counter_name」はインスタンス変数ですので、cntの変数ごとに値が違います。
クラスに共通して持つクラス変数@@cntにも、インスタンスメソッド「get_cnt」からアクセスできています。「cnt3.get_cnt」と、インスタンス変数cnt3経由で、「get_cnt」を呼んでいることに注意してください。
このように、インスタンスメソッドからは、クラス変数、インスタンス変数ともにアクセスが可能です。
クラスの変数
Rubyの変数には以下の種類があります。
このうちクラスに関する変数はインタンス変数とクラス変数とクラスインスタンス変数の3つです。前章でも記載した通り、クラスメソッドからは、クラス変数にしかアクセスできません。
また、インスタンスメソッドからはクラス変数、インスタンス変数ともにアクセスできます。クラスインスタンス変数とは、クラス変数、インスタンス変数などとは違う変数です。クラスインスタンス変数もクラスの定義内で定義する変数です。
クラス変数とクラスインスタンス変数の違いは、クラス変数はそのクラスを継承した子クラスからもアクセスできるのに対して、クラスインスタンス変数はそのクラスを継承した子クラスからはアクセスできなくなるという違いがあります。
クラス変数の扱い方に関してはこちらの記事でまとめられているので参考にしてください。
クラスの継承
Rubyの継承は「<」を使うことでできます。今回はAnimalクラスをDogクラスに継承してみましょう。
class Animal def name "animal" end def talk "Gaw" end end class Dog < Animal def talk "Bow" end def marking "CanCan" end end animal = Animal.new dog = Dog.new # 継承(機能の流用) p animal.name p dog.name # ポリモルフィズム(機能の変更) p animal.talk p dog.talk # 差分プログラミング(機能の追加) p dog.marking
[実行結果]
"animal" "animal" "Gaw" "Bow" "CanCan"
継承が成功し、DogクラスでもAnimalクラスのnameメソッドが使えていることがわかります。このようにRubyでは「<」を使用することで簡単に継承を行うことができます。
また、クラスの継承を行うと、以下のことができるようになります。
- 機能の流用
親クラスの機能をそのまま子クラスで流用すること。 - 機能の変更
ポリモルフィズム(多様性)と言い、同じメソッドを使い子クラスでメソッド動作内容を変更することで、親クラスとは違う機能を提供すること。 - 機能の追加
差分プログラミングといい、親クラスにない機能を子クラスのメソッドで追加こと。
このように、継承には機能の流用・変更・追加などの利点があります。
一つ注意点があり、Rubyは継承を1クラスしか行うことができません。そのため、複数の継承のように実装しようと思うと、後に説明するMixinという機能を使う必要があります。
クラスとモジュール
モジュールについて
モジュールを一言で表すと「インスタンス化能力はないが、メソッドを格納できるもの」です。難しく考えずにメソッドを入れるための箱なんだなという意識で大丈夫です。
モジュールは 「module」から「end」 を一つの塊として定義できます。moduleの後にはモジュール名を与えましょう。
module Number def plus(num1, num2) num1 + num2 end end
クラスの継承では機能の流用・変更・追加が可能でした。ただし、クラス間には、「継承」関係が必要で、親クラスと子クラスは継承関係の「定義」により固く結びついている必要がありました。
モジュールは、このクラスの「継承」の問題を解決するもので、「継承」の定義によらず、ばらばらなクラスに対して、モジュールを入れ込む(MixInといいます)ことにより、機能の流用・変更・追加を行うものです。
モジュールを入れ込んだクラスは、すべて同じモジュールのメソッドを使用できますので、別々のクラスなのに、まるで同じクラスであるかのように、共通の(モジュール)のメソッドを呼べます。また、呼び出すメソッドは、クラスごとに動作が異なります。
さらに、モジュールにより、クラスに新しいメソッドが追加されます。これらが「継承」の定義をせずに得られるのです。モジュールの扱い方についてはこちらにまとめられていますので参考にしてみてください。
クラスとモジュールの違い
またクラスとモジュールの違いには主に
- 定義の仕方
- 継承の有無
- インスタンスを作成できるか
- Mixinできるか
- Ruby上のどのオブジェクトなのか
です。クラスとモジュール違いについてはこちらの記事にまとめられているので参考にしてみてください。
まとめ
今回は、Rubyのclass(クラス)について学習しました。学習のポイントを振り返ってみましょう!
- クラスとはRubyに新しい「型」を追加すること。
- クラスはインスタンスという変数にすることで使用できる。
- クラスのinitializeはクラスがnewされる際に呼び出される。
- クラスのメソッドにはクラスメソッドとインスタンスメソッドがある。
- クラスの変数にはクラス変数とインスタンス変数、クラスインスタンス変数がある。
- クラスメソッドはクラス変数とクラスインスタンス変数にアクセスできる。
- インスタンスメソッドはクラス変数とインスタンス変数、クラスインスタンス変数にアクセスできる。
- クラスは継承することで、機能の流用・変更・追加ができる。
- モジュールは継承関係を使用せずに、機能の流用・変更・追加をすることができる。
以上の内容を再確認し、ぜひ自分のプログラムに生かし学習を進めてください!