タイトルの通り。
人にコードだけ見せて書き捨てるのももったいない気がしたので、説明を加筆して公開。
- わからないところがあったら質問ください
- 誤りや語弊のある表現があれば突っ込みください
オブジェクト指向とは何か、と語りはじめるとたいへん長い話になり、僕は議論できるほど理解を深めてないので 「諸説あるが」 で済ませるとして、ここではRubyのクラスベースオブジェクト指向プログラミング、つまりC++風の抽象データ型に基くOOPの話になります。 乱暴だなあ 。
class A
def initialize (arg)
# インスタンス変数(メンバ変数)定義
# これは同じインスタンスのメソッドの中からしか参照できない
@x = arg.upcase
end
# メソッド定義
def call
# インスタンス変数@xの値を取り出す
return @x
end
end
# 定数に函数を代入してる
B = ->(arg){
# 函数定義の中で変数定義
x = arg.upcase
# Bが呼びだされると、このfuncが新たに生成される
func = ->{
# この函数の中からは変数xを参照できる
# むしろxは、Bの函数定義内からしか参照できない=閉ぢてる=クロージャ
return x
}
return func
}
# インスタンス生成
a1 = A.new("foo")
# メソッド呼び出し
p a1.call
# インスタンス生成みたいなもの
b1 = B.("foo")
p b1.call
### aとa2, bとb2が新しい別のインスタンスであることを確認
# インスタンス生成
a2 = A.new("bar")
# メソッド呼び出し
p a2.call
# インスタンス生成みたいなもの
b2 = B.("baz")
p b2.call
-
a1
とa2
の@x
と、b1
とb2
から見たx
は、それぞれ別物。 -
B
内部のx
は、この場合func
からしか参照することができない-
B
と名前を付けられた函数定義が、変数のスコープを作ってる - 函数定義によって閉ぢたスコープができるから クロージャ(閉包) って呼ばれる
-
x
の中身は外部から参照したり破壊されたりしないので 隠しておける - これってつまり一般にオブジェクト指向の特徴の一つだと呼ばれることがある 「隠蔽」だよね
-
-
A
の@x
はインスタンスのメソッドからしか参照・操作できない (建前、裏技あり)- でも
A
のなかにdef x; @x; end
とかdef x= (arg); @x = arg; end
みたいなメソッドを定義すればa.x = "foo"
みたいに C# のプロパティと似たようなことができる - でもって、
attr_accessor :x
と書けば、上記の定義とまったく同じものを省略することができる。ぐぐれ。 - Ruby の世界では
x=
は一つのメソッド名。なのにa.x = "foo"
とか書けちゃう。ふしぎふしぎ。
- でも
- 僕は JavaScript とか Scheme とか素人だけど、たいへんお世話になってます
- Python はクロージャを作りにくかった(上のコードを素直に移植してもうまくいかない)んだけど、Python 3 では
nonlocal
が追加されたので作りやすくなりました - Ruby でもクロージャは使へるけど、ふつうは素直にクラスを使って表現するべき
- でも最近仕事で PHP は 変数のスコープがファイルローカルじゃない ときいて、クロージャを作って
call_user_func
で呼び出す必要があった (しろめ)
補足
- Ruby の
->(){ ... }
は函数オブジェクトを作成する構文-
lambda{ ... }
って書いてもほとんど同じなので、文脈によって読みやすさ、かっこよさで選んで良い
-
- ( あとでまた書く )
合せて読まれたい
そして突っ込みが欲しい