静岡理工科大学 菅沼ホーム Ruby 目次 索引

クラスとメソッド

  1. クラスとメソッド
    1. クラスとは
    2. クラスとメソッド
      1. クラスの定義
      2. 配列
      3. メソッド
      4. 変数と定数
      5. プログラム例
    3. 継承
    4. メソッドに対する呼び出し制限
  2. モジュール
  3. 特異クラスと特異メソッド
  4. 演算子の再定義(オーバーロード)
  5. ブロック付きメソッド呼び出し
  6. 定義に関する操作

  1. クラスとメソッド

    1. クラスとは

        クラスとは,ある「もの」に対し,その「もの」に共通する特徴等をもとにして,形式的な定義を与えたものであるといえます.もう少しプログラミング的な感覚でいえば,「もの」に共通するデータと,それらのデータを処理する方法を記述した手続き(メソッド)の集まりです.例えば,「車」というクラスを定義したとすれば,車の構造を記述するデータと車を動かしたりするのに必要な手続きからなっているはずです.また,クラスは「もの」に対する抽象的な定義ですが,インスタンスオブジェクト)はクラスを具体化したものに相当します.例えば,「車」クラスの場合であれば,オブジェクトは,ある特定の人が所有する特定の車になります.

        クラスは,その定義の方法から見て,ユーザーが新たに定義する変数の型と考えても良いと思います.新しい変数の型を定義すれば,その型の操作方法も必要になります.例えば,複素数に対応するような型をクラスによって定義したとします.すると,単純な加算ですら,既存の方法を使用することができません.従って,定義した変数の加算をどのようにして実行するかについても定義してやる必要が出てきます.そこで,クラスの定義には,単にデータだけでなく,そのデータを取り扱う方法を記述したメソッド関数)が必要になってくるわけです.

    2. クラスとメソッド

      クラスの定義

        クラスの定義は,以下のようにして行われます.なお,< の後は継承するクラスを表すものであり,次節を参照して下さい.

      class 識別子 [ < superclass ]
        式(演算式,メソッド,クラスなど)
          ・・・
      end

        クラス名はアルファベットの大文字で始まる識別子(定数)です.Ruby では,クラスもオブジェクトの一つであり,Class クラスのインスタンスです.クラス定義は,Class クラスのインスタンスを生成し,その名前を識別子で指定した定数へ代入することに相当します.そのため,C++ や Java とは異なり,後に示す例にも示すように,定義した時点で式が実行されます.

        クラスが既に定義されているとき,さらに同じクラス名でクラス定義を書くとクラスの定義の追加になります.また,クラス定義は,ネスト(入れ子)にすることもできます.クラスのネストは,意味的に関連するクラスを外側のクラスやモジュールでひとまとまりにしたり,包含関係を表すために使用されますが,継承関係などの機能的な関連はまったくありません.

      配列

        配列は,複合データ型の一種であり,複数のデータを処理する場合に利用されます.Ruby においては Array クラスのインスタンスとして定義され,例えば,
      x = Array[1, 2.3, "abc"];   # x = [1, 2.3, "abc"]; でも可
      				
      のように宣言すれば,3 つのデータを記憶できる領域が確保され,各要素に記憶される値が 1,2.3,"abc" で初期設定されます.また,変数名と添え字を利用して,x[0],x[1],x[2] のようにして参照できます.この例に示すように,各要素は,必ずしも,同じデータ型である必要はありません.しかし,間違いの元になる可能性がありますので,配列は,同じデータ型だけで構成するようにした方が良いと思います.また,プログラムの実行時に,要素の追加,削除等を行うことが可能です.

        例えば,
      u1 = Array[1, "abc", 2];
      u2 = Array[1, "abc", 2];
      u3 = u1;
      				
      の最初の 2 行では,同じ値で初期設定された 2 つの配列 u1,u2 を定義し,次の行において u1 を u3 に代入しています.しかし,この代入は,整数型の場合のような代入ではありません.つまり,u1 の領域及びそこに記憶されている要素をすべてコピーし,u3 に代入しているわけではありません.ここでは,u1,u2,u3 をポインタとしてとらえた方が理解しやすいと思います.つまり,2 行目の代入によって,u1 に記憶されているアドレスが u3 に記憶され,u1 と u3 が同じ領域を指しているという意味です.実際,u1 の値を変更すれば,u3 の値も変化します(逆も同様).配列を関数の引数として渡す場合も,ポインタを引数とすることに相当しますので,関数内で配列の要素の値を変更すれば,関数を呼んだ側における対応する要素の値も変化します.このことを概念的に示せば以下のようになります.

        多次元の配列を扱うことも可能です.例えば,
      v1 = Array[[10, 20, 30], [40, 50, 60]];
      v2 = Array[[10, 20, 30], [40, 50, 60]];
      v3 = v1;
      				
      のように,配列の要素を,さらに配列として定義すれば,2 次元の配列を定義できます.この例では,2 行 3 列の配列になります.3 行目の記述によって,v3 も,v1 と同じ 2 行 3 列の配列になります.そのイメージは,new 演算子を使用した C++ の場合と同じく,以下のようになります.

        また,
      v4 = v1[0];   // v1,v3 の 1 行目
      				
      のように,各行を 1 次元配列として扱うことも可能です.勿論,v4 と v1[0] は同じ場所を指していますので,例えば,v4[1] の値を変更すれば,v1[0][1] の値も変化します(逆も同様).しかし,すべてのデータが連続した領域に確保されるとは限らないため,異なる行のデータを,連続した 1 次元配列とみなして参照することはできません.

      メソッド

        データを処理する方法は,メソッド関数)によって記述します.メソッドは,一般的に,

      def メソッド名 [ 引数の並び ]
         式
        ・・・
        [rescue [error_type,..] [=> evar] [then]
           式..]..
        [else
           式..]
        [ensure
           式..]
      end

      のような形式で記述します.rescue 節には,本体の実行によってエラーが発生した場合の処理を記述します.else 節は,本体の実行によって例外が発生しなかった場合に評価されます.また,ensure 節が存在する時は,メソッド評価の最後に ensure 節の本体を評価します.なお,rescue 節,else 節,及び,ensure 節に関しては,制御構造の例外処理を参照して下さい.

        メソッドの戻り値は,return 節に渡した値です.return が呼び出されなかった場合は,メソッドの本体から ensure 節実行直前までの最後に評価した式の値を返します.retuen は,

      return [ 式 [ , 式 ... ] ]

      のように記述され,式が 2 つ以上与えられた時には,それらを要素とする配列をメソッドの戻り値とします.また,式が省略された場合には,nil を戻り値とします.例えば,

      return 1, 2, 3

      の場合は,3 つの値を配列に入れて返します.

        引数には,例えば,
      def func (par1, par2=10, par3=30)
      	x = par1 + par2 + par3
      	return x
      end
      print func(100, 50)
      				
      のように,デフォルト値を設定することができます(デフォルト引数).ただし,n 番目の引数にデフォルト値を設定した場合は,それ以降の引数に対してもデフォルト値を設定する必要があります.上の例の場合,3 番目の引数を省略したため,par3 の値は 30 であるとして処理され,結果は 180 になります.なお,この例の場合は,最後に処理された式の値がメソッドの返すべき値であるため,return が無くても,同じ結果になります.

        下に示す例のように,最後の仮引数の直前に * がある場合には,残りの実引数はみな配列としてこの引数に格納されます.可変長引数などと呼ばれる機能です.なお,このような引数は,1 つだけ使用できます.
      def func (par, *x)
      	p x
      end
      func(0)          # 出力結果 []
      func(1, 10)      # 出力結果 [10]
      func(2, 10, 20)  # 出力結果 [10, 20]
      				
        最後の仮引数の直前に & があると,このメソッドに与えられているブロックが Proc クラスのオブジェクトとしてこの引数に格納されます.このような引数も,1 つだけ使用できます.詳細については,「ブロック付きメソッド呼び出し」を参照して下さい.

        メソッド定義において,仮引数はその種類毎に,以下に示す順序でしか指定することはできません.なお,いずれも省略することは可能です.

      • デフォルト式のない引数(複数指定可)
      • デフォルト式のある引数(複数指定可)
      • * を伴う引数(1つだけ指定可)
      • & を伴う引数(1つだけ指定可)

      変数と定数

        Ruby の変数と定数の種別は変数名の最初の 1 文字によって,ローカル変数インスタンス変数クラス変数(次節参照),グローバル変数定数のいずれかに区別されます.2 文字目以降は英数字,または,_ であり,変数名の長さにはメモリのサイズ以外の制限はありません.

        小文字,または,_ で始まる識別子はローカル変数,または,メソッド呼び出しです.ローカル変数の有効範囲(スコープ)は,その変数を宣言した位置から,その変数が宣言されたブロック,メソッド定義,または,クラス/モジュール定義の終りまでです.また,$ で始まる変数はグローバル変数であり,プログラムのどこからでも参照できます.

        アルファベット大文字( [ A - Z ] )で始まる識別子は定数です.定数の定義は代入によって行われますが,メソッドの中では定義できません.また,一度定義された定数に再び代入を行おうとすると,警告メッセージが出ます(代入は可能です).定数は,その定数が定義されたクラス/モジュール定義の中(メソッド本体やネストしたクラス/モジュール定義中を含みます),クラスを継承しているクラス,モジュールをインクルードしているクラス,または,モジュールから参照することができます.

        @ で始まる変数は,インスタンス変数であり,特定のオブジェクトに所属しています.インスタンス変数はそのクラスまたはサブクラスのメソッドから参照できます.インスタンス変数は,クラスから生成されたインスタンス(オブジェクト)毎に別の値を持つことができるため,各オブジェクトの状態を表すためなどに使用されます.このように,インスタンス変数は,C/C++ における protected 指定されたメンバー変数と似た働きをします.従って,そのままでは,クラスの外部から参照することはできません.参照可能にするためには,Module クラス内の記述を参考にしてください.

      プログラム例

        以下に示すのは,クラスの定義・参照方法,及び,変数・定数の使用方法に関するプログラム例と出力結果です.このプログラムにおいて,printf は,組み込み関数,つまり,Kernel モジュールで定義されているメソッドであり,全てのクラスから参照できます.Object クラスは,このモジュールをインクルードしています.printf は,C/C++ における printf 関数と似たメソッドであり,ほとんど同じように使用することができます.ただし,C/C++ とは異なり,引数リストを必ずしも括弧で囲む必要はありません(下に示すいずれの方法も可能).なお,この点は,他のメソッドにおいても同様です.
      printf "x = %d\n", x
      printf ("x = %d\n", x)
      				
      01	v_local_1  = 10
      02	$_global_1 = 100
      03	Const_1    = 1000
      04
      05	class Test
      06		v_local_2  = 20
      07		$_global_2 = 200
      08		Const_2    = 2000
      09		#printf "   ローカル変数 v_local_1 = %d (in class)\n", v_local_1  参照不可能
      10		printf "   グローバル変数 $_global_1 = %d (in class 変更前)\n", $_global_1
      11		$_global_1 = 500
      12		printf "   グローバル変数 $_global_1 = %d (in class 変更後)\n", $_global_1
      13		printf "   定数 Const_1 = %d (in class 定義前)\n", Const_1
      14		Const_1 = 5000
      15		printf "   定数 Const_1 = %d (in class 定義後)\n", Const_1
      16		printf "   ローカル変数 v_local_2 = %d (in class)\n", v_local_2
      17		printf "   グローバル変数 $_global_2 = %d (in class)\n", $_global_2
      18		printf "   定数(初期化) Const_2 = %d (in class)\n", Const_2
      19		def initialize(par = 100)
      20			@_par = par
      21		end
      22		def out
      23			printf "定数 Const_2 = %d, インスタンス変数 @_par = %d\n", Const_2, @_par
      24		end
      25	end
      26
      27	printf "\nローカル変数 v_local_1 = %d\n", v_local_1
      28	printf "グローバル変数 $_global_1 = %d\n", $_global_1
      29	printf "定数 Const_1 = %d\n", Const_1
      30	print "\n"
      31	#printf "   ローカル変数 v_local_2 = %d\n", v_local_2  参照不可能
      32	printf "グローバル変数 $_global_2 = %d\n", $_global_2
      33	printf "定数 Test::Const_1 = %d\n", Test::Const_1
      34	printf "定数 Test::Const_2 = %d\n", Test::Const_2
      35	print "\n"
      36	t_obj1 = Test.new
      37	t_obj1.out
      38	t_obj2 = Test.new 200
      39	t_obj2.out
      40	t_obj3 = Test.new(300)
      41	t_obj3.out
      42	print "\n"
      43	Test::Const_2 = 3000
      44	printf "定数(代入後) Const_2 = %d\n", Test::Const_2
      45
      46	print "\n"
      47	class Test_o
      48		printf "   定数 Const_1 = %d (in class Test_o)\n", Const_1
      49		printf "   定数 Const_2 = %d (in class Test_o)\n", Test::Const_2
      50	end
      
      (出力結果)
      
      01	   グローバル変数 $_global_1 = 100 (in class 変更前)
      02	   グローバル変数 $_global_1 = 500 (in class 変更後)
      03	   定数 Const_1 = 1000 (in class 定義前)
      04	   定数 Const_1 = 5000 (in class 定義後)
      05	   ローカル変数 v_local_2 = 20 (in class)
      06	   グローバル変数 $_global_2 = 200 (in class)
      07	   定数(初期化) Const_2 = 2000 (in class)
      08
      09	ローカル変数 v_local_1 = 10
      10	グローバル変数 $_global_1 = 500
      11	定数 Const_1 = 1000
      12
      13	グローバル変数 $_global_2 = 200
      14	定数 Test::Const_1 = 5000
      15	定数 Test::Const_2 = 2000
      16
      17	定数 Const_2 = 2000, インスタンス変数 @_par = 100
      18	定数 Const_2 = 2000, インスタンス変数 @_par = 200
      19	定数 Const_2 = 2000, インスタンス変数 @_par = 300
      20
      21	test.rb:43: warning: already initialized constant Const_2
      22	定数(代入後) Const_2 = 3000
      23
      24	   定数 Const_1 = 1000 (in class Test_o)
      25	   定数 Const_2 = 3000 (in class Test_o)
      				
        まず,1 ~ 3 行目において,ローカル変数 v_local_1,グローバル変数 $_global_1,及び,定数 Const_1 を定義しています.次の 5 ~ 25 行目において,クラス Test を定義しています.クラス定義の中では,各種変数,定数,及び,2 つのメソッドを定義しています.out は,インスタンス変数 @_par を出力するために作成したメソッドであり,また,initialize は,Object クラスのメソッドであり,その内容をこのクラス用にオーバーライド(書き直し)しています.

        クラスに対するインスタンスの生成には,36,38,及び,40 行目に示すように,Class クラスの new メソッドを利用します.new メソッドを利用してインスタンスを生成すると,もし,クラス定義の中に initialize が記述してある場合,その内容が最初に実行されます.つまり,initialize メソッドは,C/C++ や Java におけるコンストラクタに相当します.この例の場合,引数が 1 つで,かつ,そのデフォルト値が 100 である initialize が定義されており,その中で,受け渡された引数をインスタント変数に代入しているため,異なるインスタンス変数の値を持つインスタンスを生成することが可能です(他の定数・変数については共通).

        先に述べたように,クラス定義は,Class クラスのオブジェクトを生成することになりますので,クラス定義を行うだけで,その中に記述された printf メソッドによる出力結果が表示されます.しかし,new メソッドによるインスタンス生成の際には表示されません.これらの点は,C/C++ や Java におけるクラス定義と大きく異なります.つまり,Ruby においては,単なるクラスの定義ではないのです.

        次に,変数や定数について眺めてみます.1 行目で定義されたローカル変数 v_local_1 は,クラス定義の中では参照できません.逆に,クラス定義の中の 6 行目で定義されたローカル変数 v_local_2 は,クラス定義の外からは参照できません.しかし,グローバル変数 $_global_1 や $_global_2 は,どこからも参照でき,かつ,同じ変数名であれば,すべて同じ変数を表しています.

        定数は,再代入する際に警告メッセージが出力される( 43 行目)点を除くと,参照できる範囲の点から,グローバル変数と非常に似ています.しかし,そのスコープがクラスやモジュールの内部に制限されているため,多少異なってきます.13 行目において,定数 Const_1 の値を出力する際は,3 行目で定義された Const_1 を参照しています.しかし,14 行目においてクラス内で定数 Const_1 が定義されると,それ以降のクラス内においては,この定数が有効になります.つまり,3 行目で定義された Const_1 と,クラス内で定義された Const_1 は異なった定数になります.そして,クラスの外からクラス内の定数 Const_1 を参照するためには.「 Test::Const_1 」のように表記する必要があります.同じように,クラス内のメソッドを呼び出すためには,37,39,及び,41 行目のように,「 . 」を使用します.

    3. 継承

        あるクラスに宣言されているメソッドなどをすべて受け継ぎ(メソッドなどを利用できるようにする),それに新たなメソッドを追加,受け継いだメソッドの修正などを行い,新しいクラスを宣言することができます.これを,クラスの継承と呼びます.このとき,基になったクラスをスーパークラス(親クラス),新たに作成したクラスをサブクラス(子クラス)と呼びます.継承するクラスを示すためには,下の例に示すように, < を使用します.なお,Ruby においては,多重継承は許されません.

        @@ で始まる変数はクラス変数と呼びます.クラス変数は,クラス定義の中で定義され,そのクラス,及び,そのサブクラスから参照できます.このような点から,クラス変数は,クラスやサブクラスなどで共有されるグローバル変数であるとみなすことができます.

        以下に示すプログラム例において,クラス Test は,クラス P_Test を継承しています.また,Ruby のプログラムを書くことは,Object クラスを継承したクラスを定義することに相当しますので,例に示すプログラム全体が,Object クラスを継承したサブクラスになっています.従って,プログラムのどこからでも,Object クラスに定義されているメソッドやクラス変数を参照可能です.

        クラス P_Test で定義されているクラス変数 @@_class やメソッド func は,クラス P_Test を継承しているクラス Test からも参照可能です.しかし,クラス Test 内にネストされたクラス Test_in (クラス Test との機能的な関係はない)やクラスの外からは参照できません.
      class P_Test
      	@@_class = 10
      	printf "クラス変数 @@_class = %d (in P_Test)\n", @@_class
      	def func
      		printf "こんにちは!!"
      	end
      end
      
      class Test < P_Test
      	printf "クラス変数 @@_class = %d (in Test)\n", @@_class
      	class Test_in
      #		printf "クラス変数 @@_class = %d (in Test)\n", @@_class  参照不可能
      	end
      end
      
      #printf "クラス変数 @@_class = %d\n", @@_class  参照不可能
      t_obj1 = P_Test.new
      t_obj1.func
      printf " (in P_Terst)\n"
      t_obj2 = P_Test.new
      t_obj2.func
      printf " (in Terst)\n"
      				
      (出力)
      クラス変数 @@_class = 10 (in P_Test)
      クラス変数 @@_class = 10 (in Test)
      こんにちは!! (in P_Terst)
      こんにちは!! (in Terst)
      				
        super は現在のメソッドがオーバーライドしているスーパークラスのメソッドを呼び出します.括弧と引数が省略された場合には現在のメソッドの引数がそのまま引き渡されます.引数を渡さずにオーバーライドしたメソッドを呼び出すには super() と括弧を明示します.以下に示すプログラムを実行すると,250 という出力が得られます.
      class P_Test
      	def add(p1, p2=20, p3=30)
      		return p1 + p2 + p3
      	end
      end
      
      class Test < P_Test
      	def add(p)
      		return p + super
      	end
      end
      
      print Test.new.add(100)
      				

    4. メソッドに対する呼び出し制限

        メソッドは,publicprivateprotected の三通りの呼び出し制限を持ちます.public に設定されたメソッドは制限なしに呼び出せます.private,及び,protected に設定されたメソッドは,そのメソッドを持つオブジェクトのメソッド定義式内でなければ呼び出せません.また,private に設定されたメソッドは,関数形式( obj.func のように,ピリオドでオブジェクトを指定した部分がない形式)でしか呼び出せません.デフォルトでは,def 式がクラス定義の外(トップレベル)にあれば private,クラス定義の中にあれば public に定義します.

        下に示す例においては,メソッド func_private は private,メソッド func_protected は protected,その他は public に設定してあります.例えば,private を記述すると,それ以降のメソッドはすべて private になります.しかし,

      private :func_private
      protected :func_protected

      などの記述により,変更することが可能です.なお,この例において,self は自分自身のオブジェクトを指します.また,new は,新しいオブジェクトを生成するためのメソッドです.例えば,「 Test.new.func_public 」は,Test クラスのオブジェクトを生成し,そのクラスに定義されているメソッド func_public を呼ぶことを意味しています.このように,引数を持たないメソッドを呼ぶときは,括弧も必要ありません.
      01	class Test
      02		def func
      03			Test.new.func_protected
      04			printf " (in Method)\n"
      05			self.func_protected
      06			printf " (in Method)\n"
      07			func_private
      08			printf " (in Method)\n"
      09	#		self.func_private  関数形式だけが許される
      10		end
      11		def func_public
      12			printf "public method"
      13		end
      14		private
      15			def func_private
      16				printf "private method"
      17			end
      18		protected
      19			def func_protected
      20				printf "protected method"
      21			end
      22		Test.new.func_public
      23		printf " (in Class)\n"
      24	#	Test.new.func_protected   この位置では呼べない
      25	#	func_private   この位置では呼べない
      26	end
      27	
      28	Test.new.func_public
      29	printf "\n"
      30	Test.new.func
      				
      (出力)
      public method (in Class)      # 22, 23 行目の実行
      public method                 # 28, 29 行目の実行
      protected method (in Method)  # 30 行目の実行(メソッド func の実行)
      protected method (in Method)  # 30 行目の実行(メソッド func の実行)
      private method (in Method)    # 30 行目の実行(メソッド func の実行)
      				

  2. モジュール

      Ruby では,多重継承(複数のクラスを継承する機能)を許していません.その代わりに,モジュールという機能があります.モジュールはインスタンスを持たないクラスといっても良いかもしれません.クラスの定義において,Module クラスの include メソッドによりモジュールの機能を取りこんで使用します.このことを,Mix-in と呼びます.下の例では,モジュール Add_m をクラス Test に取り込んでいます.実行すると,30 と 90 という結果が得られます.
    module Add_m
    	Const = 100
    	def add(a, b)
    		return a + b
    	end
    end
    
    class Test
    	include Add_m
    	def sub(a, b)
    		return a - b + Const
    	end
    end
    
    printf "%d\n", Test.new.add(10, 20)
    printf "%d\n", Test.new.sub(10, 20)
    			
      下に示す例のように,クラスではなく特定のオブジェクトにだけモジュールの機能を追加することも可能です.その際には,Object クラスの extend メソッドを使用します。
    module Add_m
    	Const = 100
    	def add(a, b)
    		return a + b
    	end
    end
    
    class Test
    	include Add_m
    	def sub(a, b)
    		return a - b + Const
    	end
    end
    
    obj = Test.new
    obj.extend Add_m
    printf "%d\n", obj.add(10, 20)
    printf "%d\n", obj.sub(10, 20)
    			

  3. 特異クラスと特異メソッド

      特異クラス定義式を利用すると,クラス定義と同じような構文で(<< によってオブジェクトを指定),特定のオブジェクトにメソッドやインスタンス変数を定義/追加できます.この定義式の内部で定義したメソッドや定数は,指定したオブジェクトに対してだけ有効になります.Object クラスの clone や dup は,オブジェクトの複製を作成して返すメソッドですが,特異クラス定義式によって変更されたオブジェクトは,clone で生成したオブジェクトには引き継がれますが,dup で生成したオブジェクトには引き継がれません.以下に,特異クラス定義式を使用したプログラムとその出力結果を示しますが,この例では,メソッド func をオーバーライドしています.
    class Test
    	def func
    		printf "クラス Test\n"
    	end
    end
    
    obj1 = Test.new
    obj2 = Test.new
    
    class << obj2
    	def func
    		printf "クラス Test\n"
    		printf "   こんにちは!!\n"
    	end
    end
    
    obj1.func
    obj2.func
    			
    (出力)
    クラス Test
    クラス Test
       こんにちは!!
    			
      特異メソッドとは,特異クラスと似ていますが,特異クラスのようにオブジェクト全体の変更ではなく,ある特定のオブジェクトのメソッドだけを対象とした追加/修正です.上の例を,特異メソッドの定義式を使用して書き直すと以下のようになります.
    class Test
    	def func
    		printf "クラス Test\n"
    	end
    end
    
    obj1 = Test.new
    obj2 = Test.new
    
    def obj2.func
    	printf "クラス Test\n"
    	printf "   こんにちは!!\n"
    end
    
    obj1.func
    obj2.func
    			
      クラスメソッドとは,Java における static メソッドに相当し,

    クラス名.メソッド名

    という方法で参照できます.クラスメソッドは,クラスの特異メソッドとして定義されます.Ruby では,クラスもオブジェクトですので,普通のオブジェクトと同様に特異メソッドを定義できます.したがって,何らかの方法でクラスオブジェクトにメソッドを定義すれば,それがクラスメソッドとなります.具体的には,以下のようにして定義することが出来ます(モジュールも同様です).なお,クラスの特異メソッドはそのサブクラスにも継承されます.
    class Test
    	def func
    		printf "クラス Test\n"
    	end
    end
    
    def Test.func
    	printf "クラス Test\n"
    	printf "   こんにちは!!\n"
    end
    
    Test.func
    			

  4. 演算子の再定義(オーバーロード)

      「再定義可能な演算子」に分類された演算子の実装はメソッドですので,再定義することが可能です.それらの演算子を定義する例を以下に示します.

    # 二項演算子
      def +(other)   # obj + other
      def -(other)   # obj - other
    # 単項プラス/マイナス
      def +@   # +obj
      def -@   # -obj
    # 要素代入
      def foo=(value)   # obj.foo = value
    # [] と []=
      def [](key)          # obj[key]
      def []=(key, value)      # obj[key] = value
      def []=(key, key2, value)   # obj[key, key2] = value

      以下,+ 演算子,単項 - 演算子,及び,代入演算子に対するプログラム例と出力例を示します.

    + 演算子
    class Comp
    	def initialize(_real = 0, _imag = 0)
    		@_real = _real
    		@_imag = _imag
    	end
    	def out(cr = "")
    		printf "(%f, %f)%s", @_real, @_imag, cr
    	end
    	def real
    		return @_real
    	end
    	def imag
    		return @_imag
    	end
    	def +(obj)
    		c = Comp.new(@_real+obj.real, @_imag+obj.imag)
    		return c
    	end
    end
    
    a = Comp.new(1, 2)
    b = Comp.new(2, 3)
    a.out("\n")
    b.out("\n")
    c = a + b
    c.out("\n")
    			
    (出力)
    (1.000000, 2.000000)
    (2.000000, 3.000000)
    (3.000000, 5.000000)
    			
    単項 - 演算子
    class Comp
    	def initialize(_real = 0, _imag = 0)
    		@_real = _real
    		@_imag = _imag
    	end
    	def out(cr = "")
    		printf "(%f, %f)%s", @_real, @_imag, cr
    	end
    	def -@
    		c = Comp.new(-@_real, -@_imag)
    		return c
    	end
    end
    
    a = Comp.new(1, 2)
    a.out("\n")
    c = -a
    c.out("\n")
    			
    (出力)
    (1.000000, 2.000000)
    (-1.000000, -2.000000)
    			
    代入
    class Comp
    	def initialize(_real = 0, _imag = 0)
    		@_real = _real
    		@_imag = _imag
    	end
    	def out(cr = "")
    		printf "(%f, %f)%s", @_real, @_imag, cr
    	end
    	def real=(x)
    		@_real = x
    	end
    	def imag=(x)
    		@_imag = x
    	end
    end
    
    a = Comp.new(1, 2)
    a.out("\n")
    a.real = 10
    a.imag = 20
    a.out("\n")
    			
    (出力)
    (1.000000, 2.000000)
    (10.000000, 20.000000)
    			

  5. ブロック付きメソッド呼び出し

      ブロックとは,{ ... },または,do ... end のペアで囲まれた Ruby の文及び式の集まりです.ブロックの先頭には,縦棒 ( | ) で囲み,パラメータをカンマで区切って指定できます.ブロックは,

    method(arg1, arg2, ...) do [ | 式 ... | ] 式 ... end
    method(arg1, arg2, ...) { [ | 式 ... | ] 式 ... }
    method(arg1, arg2, ..., &proc_object) # proc_object は別に定義

    のような形式で,メソッドに引数として渡すことができます.ブロックを引数として受け取るメソッドを,ブロック付きメソッドと呼びます.C/C++ について知っている人は,C/C++ における関数名を引数として渡す方法(関数のアドレスを引数として渡す方法)として考えれば分かり易いかと思います.ブロック付きメソッドは,制御構造の抽象化のために用いられるメソッドであり,最初はループの抽象化のために用いられていたため,特にイテレータと呼ばれることもあります.イテレータとは,簡単に言えば,以下のようなものです.通常の配列であれば,添え字などによって簡単に各要素を参照できます.しかし,その構造が複雑な場合は,それほど簡単ではありません.そこで,それを簡単に行えるようにしたものがイテレータです.

      以下に示すプログラムは,Integer クラスのブロック付きメソッドである times の使用例です.times は,与えられたブロックを self 回だけ( 0 から self-1 まで)繰り返します.1 行目ではパラメータを指定せず,2 行目では 1 つだけ指定しています.また,3 行目,及び,6 行目は,Proc クラスの new メソッドを使用してブロックオブジェクトを生成した後,それを引き渡しています.ブロックオブジェクトの生成は,4 行目,及び,5 行目に示すように,組み込み関数である proc や lambda によっても可能です(コメント部分).
    3.times {printf "test\n"}
    3.times {|m| printf "m = %d\n", m; printf "   result %d\n", 3*m}
    block = Proc.new {printf "test\n"}
    	# block = proc {printf "test\n"} この方法でも可
    	# block = lambda {printf "test\n"} この方法でも可
    3.times &block
    			
    test
    test
    test
    m = 0
       result 0
    m = 1
       result 3
    m = 2
       result 6
    test
    test
    test
    			
      yieldは,自分で定義したブロック付きメソッドにおいて,ブロックを呼び出すときに使われ,次のような形式で記述されます.
    yield ( [ 式 [, 式 ・・・ ] ] )
    yield [ 式 [, ' 式 ・・・ ] ]
    			
      yield に渡された値は,ブロック記法において | と | の間にはさまれた変数(ブロックの引数)に代入されます.また,Proc クラスの call メソッドを使ってブロックを実行することもできます.以下に示すプログラムは,上で述べた times を新たに定義した _times で置き換えた例です.
    def _times(n, &block)
    	k = 0
    	while k < n
    		yield(k)   # block.call k でも可
    		k += 1
    	end
    end
    
    block = Proc.new {|m| printf "m = %d\n", m; printf "   result %d\n", 3*m}
    _times 3, &block
    			

  6. 定義に関する操作

    alias

      メソッドあるいはグローバル変数に別名をつけます.

    alias 新メソッド名 旧メソッド名
    alias 新グローバル変数名 旧グローバル変数名

    undef

      メソッドの定義を取り消します.

    undef メソッド名[, メソッド名[, ...]]

    defined?

      式が定義されていなければ,偽を返します.定義されていれば式の種別を表す文字列を返します.

    defined? 式

静岡理工科大学 菅沼ホーム Ruby 目次 索引