+や-は演算子ですか+や-などは演算子ではなくメソッド呼び出しです.したがって
オーバーライドすることもできます.
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
こんなことができるわけです.