+
や-
は演算子ですかprivate
とprotected
の違いが分かりませんsuper
がArgumentError
になりますが特異メソッド、自クラスで定義されたメソッド、スーパークラス(Mix-inされた
モジュールを含む。クラス名.ancestorsで表示される。)で定義されたメソッドの順に
最初に見つかったメソッドが実行されます。メソッドが見つからなかった
場合には、method_missing
が同じ順で捜されます。
Module Indexed def [](n) to_a[n] end end Class String include Indexed end p String.ancestors # [String, Indexed, Enumerable, Comparable, Object, Kernel] p "abcde".gsub!(/./, "\\&\n")[1]
は、残念ながら期待するように"b\n"を返してくれず、10を返してきます。 []がStringクラスで捜され、Indexedで定義されたものを捜し出す前に マッチしてしまうからです。Class Stringで直接[]を再定義すれば、 期待どおりになります。
+
や-
は演算子ですか+
や-
などは演算子ではなくメソッド呼び出しです。したがって
オーバーロードすることもできます。
class MyString < String def +(other) print super(other) end end
ただし、以下のもの及びこれらを組み合わせたもの(!=、!~)は制御構造であり、 オーバーロードできません。
=, .., ..., !, not, &&, and, |, or, ~, ::
単項演算子をオーバーロード(もしくは定義)するには、メソッド名として
+@
や-@
を使います。
=
は、インスタンス変数へのアクセスメソッドとして,
クラス定義の中で次のようにメソッドを定義することができます。
また、+
や-
なども定義することにより、+=
などの自己代入演算も可能になります。
def attribute=(val) @attribute = val end
Rubyにおいて関数のように見えるものはすべてレシーバ(self)を省略した形の メソッドです。例えば
def writeln(str) print(str, "\n") end writeln("Hello, World!")
のように一見関数のように見えるものも、Objectクラスに定義された
メソッドであり、隠されたレシーバーself
に送られているというわけです。
したがってRubyを純粋なオブジェクト指向言語と呼ぶことができます。
組込み関数のように、self
が何であっても同じ結果を返すメソッドは、
レシーバーを意識する必要がありませんので、関数と考えてもいいという
ことになります。
直接はできません。あらかじめそのオブジェクトにインスタンス変数を 参照するためのメソッド (アクセサと言います) を定義しておく必要が あります。たとえば以下のようにします。
class C def name @name end def name=(str) # name の後に空白を入れてはいけない! @name = str end end c = C.new c.name = 'やまだたろう' p c.name #=> "やまだたろう"
またこのような単純なメソッド定義は Module#attr
、attr_reader
、
attr_writer
、attr_accessor
などを使って簡潔に行うことができます。
たとえば上にあったクラス定義は以下のように書き直せます。
class C attr_accessor :name end
なんらかの理由でアクセスメソッドは作りたくないけれど参照はしたい場合は
Object#instance_eval
を使って参照することもできます。
private
とprotected
の違いが分かりませんprivate
の意味は、メソッドを関数形式でだけ呼び出せるようにし、
レシーバー形式では呼び出せないようにするという意味です。したがって、
可視性がprivate
なメソッドは、自クラス及びサブクラスからしか参照
できません。
protected
も同様に、自クラス及びサブクラスからしか参照できませんが、
関数形式でもレシーバー形式でも呼び出せます。
メソッドのカプセル化に必要な機能です。
インスタンス変数をpublicにすることはデータのカプセル化という観点から見
て好ましくありませんので、Rubyではインスタンス変数へのアクセスはアクセス
メソッドを使って行います。attr
メソッドを使うことで外部からみると
変数にアクセスしているかのように振舞わせることが可能です。
class Foo def initialize(str) @name = str end attr("name") # これはこういうことです。 # def name # return @name # end end foo = Foo.new("Tom") print foo.name, "\n" # Tom
attr(name, public)
で省略可能な二番目の引数にtrue
を指定するこ
とで書き込みメソッドを提供することも可能です。
class Foo def initialize(str) @name = str end attr("name", true) # これはこういうことです。 # def name # return @name # end # def name=(str) # @name = str # end end foo = Foo.new("Tom") foo.name = "Jim" print foo.name, "\n" # Jim
Module#attr_reader
, attr_writer
, attr_accessor
も
参照してください。
最初に断わっておくと、Rubyでは関数形式(レシーバを省略した形)でしか呼び 出すことのできないメソッドのことをprivateなメソッドと呼びます。ちょっ と変ってますね。
クラスのメソッドをprivateにすれば外部から呼び出すことができなくなりま す(ただしそのクラスのサブクラスからは呼び出すことができます)。クラス 内でしか呼び出すことのないメソッドはprivateにしておくとよいでしょう。
次のようにすればメソッドをprivateにすることができます。
class Foo def test print "hello\n" end private :test end foo = Foo.new foo.test #=> test.rb:9: private method `test' called for #<Foo:0x400f3eec>(Foo)
クラスメソッドをprivateにするにはprivate_class_method
を使います。
class Foo def Foo.test print "hello\n" end private_class_method :test end Foo.test #=> test.rb:8: private method `test' called for Foo(Class)
同様にpublic
、public_class_method
を用いることでメソッドを
publicにすることができます。
デフォルトでは、クラス内でのメソッド定義はinitializeを除いてpublic、 トップレベルではprivateになっています。
使えます。ただし、引数の無いメソッド呼出しに対して引数を括る()を省略できません。
super
がArgumentErrorになりますがメソッド定義中でsuper
と呼び出すと、引数がすべて渡されますので、
引数の数が合わないとArgumentErrorになります。異なる数の引数を
指定するには、super()
に引数を指定してやります。
super
は、1段上の同名のメソッドを呼び出します。それより上の同名の
メソッドを呼び出すには、あらかじめそのメソッドをaliasしておきます。
メソッド定義の中ではsuper
が使えます。再定義する前にalias
しておくと、元の定義が保たれます。
Kernelの特異メソッドとしても呼べます。
オブジェクトの内容を変更してしまうメソッドで、文字列や配列、ハッシュ などにあります。同名のメソッドがあって、一方はオブジェクトのコピーを 作って返し、もう一方は変更されたオブジェクトを返すようになっている場合、 !のついた方が破壊的メソッドです。String#concatのように!がつかない メソッドでも破壊的なものはあります。
実引数であるオブジェクトに対して、メソッドの中から破壊的メソッドを 適用した場合です.
def foo(str) str.sub!(/foo/, "baz") end obj = "foo" foo(obj) print obj #=> "baz"
この場合、引数となったオブジェクトが変更されています。でも、これは、プログラム の中で必要があって副作用のあるメッセージをオブジェクトに対し て送っているので当たり前です。
Rubyでは、メソッドの戻り値は一つしか指定できませんが、 配列を使うことによって、複数の戻り値を返すことができます。
return 1, 2, 3
とすると配列が返されます。つまり、
return [1, 2, 3]
とするのと同じです。
さらに多重代入を利用すると、複数の戻り値を戻すのとほとんど同じことがで きます。たとえば、
def foo return 20, 4, 17 end a, b, c = foo print "a:", a, "\n" #=> a:20 print "b:", b, "\n" #=> b:4 print "c:", c, "\n" #=> c:17
こんなことができるわけです。