+
や-
は演算子ですか+
や-
などは演算子ではなくメソッド呼び出しです.したがって
オーバーライドすることもできます.
class MyString < String
def +(other)
print super(other)
end
end
ただし,以下のものは制御構造であり,オーバーライドできません.
=, .., ..., !, not, &&, and, |, or, !=, ~
単項演算子をオーバーライドするには,メソッド名として+@
や-@
を
使います.
厳密に言えばRubyに関数はありません.Rubyにおける関数(みたいなもの)はす べてレシーバを省略した形のメソッドです.例えば
def writeln(str)
print(str, "\n")
end
writeln("Hello, World!")
のように一見関数のように見えるものも,main
というオブジェクトのメ
ソッドです.したがってRubyを純粋なオブジェクト指向言語と呼ぶことができ
るわけです.
でも使う時はメソッドであることを意識する必要はありません.
インスタンス変数を参照するメソッドが定義されていれば,そのメソッドを
使って値を知ったり,値をセットしたりすることができます.
Module#attr
,attr_reader
,attr_writer
,attr_accessor
を参照してください.
もちろん,自分でメソッドを定義して参照することもできます.
method=
の形のメソッド定義は,method
と=
の間に空白をいれることが
できませんが,メソッド呼出しの時には,空白をいれることが可能ですし,
+,-などのメソッドが定義されていれば,+=,-=などの自己代入も行えます.
Object#instance_eval
を使えば,直接参照することもできます.
private
とprotected
の違いが分かりませんprivate
の意味は,メソッドを関数形式でだけ呼び出せるようにし,
レシーバー形式では呼び出せないようにするという意味です.したがって,
可視性がprivate
なメソッドは,自クラス及びサブクラスからしか参照
できません.
protected
も同様に,自クラス及びサブクラスからしか参照できませんが,
関数形式でもレシーバー形式でも呼び出せます.
メソッドのカプセル化に必要な機能です.
できません.
インスタンス変数をpublicにすることはデータのカプセル化という観点から見
てあまり好ましくありません.インスタンス変数へのアクセスはアクセスメソッ
ドを介して行われます.Rubyではattr
メソッドを使うことで外部に
は変数のように振舞わせることが可能です.
class Foo
def initialize(str)
@name = str
end
attr("name")
# This means:
# 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になっています.
*
は何ですかCウィザードのみなさん,これはポインタではありません.Rubyでは引数に
*
を付けることで,不定個の引数を配列に格納した形で受け取ることがで
きます.
def foo(*all)
for e in all
print e, " "
end
end
foo(1, 2, 3)
# -> 1 2 3
またメソッド呼び出しで*
を付けた配列を渡すと配列を展開して渡すこと
ができます.
a = [1, 2, 3]
foo(*a)
現在,*
をつけることができるのは
の末尾だけです.(1)は
x, *y = [7, 8, 9]
のような形式で,この場合 x
= 7,y
= [8, 9] になり
ます.
x, = [7, 8, 9]
のような記述もでき,この場合,x
= 7 で
x = [7, 8, 9]
なら,x
= [7, 8, 9] になります.
できます.
しかもこのデフォルト値は関数の呼び出し時に評価されます.Rubyのデフォル ト値は任意の式が可能で(C++はコンパイル時に決まる定数のみ),評価はメソッ ドのスコープで呼び出し時に行われます.
参照渡しです.したがって,参照されているオブジェクトが,自分の 状態を変更するメソッドを持っている時には,副作用(それが主作用かも しれませんが)に注意する必要があります.
値渡しでなくて参照渡しなのは,関数呼び出しのたびにオブジェクトがコピー されるのを防ぐためです.これは,Cで配列や文字列がポインタで渡ること,構造体を ポインタで渡すことが多いことと同じです.また,Smalltalkやlispの実装は Rubyと全く同じです.
使えます.ただし,メソッド呼出しの時に引数を括る()を省略できません.
super
がArgumentError
になりますがメソッド定義中でsuper
と呼び出すと,引数がすべて渡されますので,
引数の数が合わないとArgumentError
になります.異なる数の引数を
指定するには,super()
に引数を指定してやります.
super
は,1段上の同名のメソッドを呼び出します.それより上の同名の
メソッドを呼び出すには,あらかじめそのメソッドをaliasしておきます.
メソッド定義の中ではsuper
が使えます.再定義する前にalias
しておくと,
元の定義が保たれます.Kernel
の特異メソッドとしても呼べます.
オブジェクトの内容を変更してしまうメソッドで,文字列や配列,ハッシュ などにあります.同名のメソッドがあって,一方はオブジェクトのコピーを 作って返し,もう一方は変更されたオブジェクトを返すようになっている場合, !のついた方が破壊的メソッドです.
a +b
がエラーになりますがa(+b)
と解析されています.+
の両側の空白をなくすか,いれるか
のどちらかにしてください.
s = "x"; puts s *10
がエラーになりますがputs s *10
のところが,s(*10)というメソッド呼出しと解析されて
しまいます.s*10
にするか,s * 10
にしてください.
p {}
で何も表示されません{}がハッシュのコンストラクタではなく,ブロックと解析されています. p({})としてください.
def pos= (val) print @pos,"\n"; @pos = val end
と定義しても,pos = 1
で参照できません=
のついたメソッドは,レシーバー形式で呼ぶ必要があります.
self.pos = 1
という形で呼んでください.
実引数となったオブジェクトに対して,メソッドの中から破壊的メソッドを 適用した場合です.
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
こんなことができるわけです.