はじめに
作業しながらも、継承の影響範囲ってどこまでだっけ。。とか
この場合のselfは何を指しているんだっけ。。とか
基礎部分をフワッとしか理解できていなかったので今回は
- クラス
- 継承
- self
- ネスト
といった内容を、実際に書きながら学んでいったのでその記録として書きます。
メソッドや変数のことも書きたいのですが、長くなりそうなので別で書きたいと思います。
クラスの継承
クラスを定義する際にスーパークラスを1つ指定することができ、
この時に指定しない場合は、自動的にobjectクラスを継承します。
そのため、クラスを新しく定義する時は常に何かのクラスを継承する形になり
必ず継承ツリーのどこかに入ることになります。
継承する対象
- スーパークラスのクラスメソッド
- インスタンスメソッド
- メソッド内に記述されているインスタンス変数
また、継承ではありませんが、スーパークラスの定数、クラス変数も参照できます。
class Klass
VALUE = "I'm VALUE"
@@class_val = "I'm class_val"
end
class A < Klass
end
class B < A
def self.display_bal
puts @@class_val
end
end
# スーパークラスの定数の参照
puts B::VALUE
# => I'm VALUE
# クラス変数の継承
B.display_val
# => I'm class_val
self
self
はオブジェクトそのものを指すので、使用する場所によって中身が変わります。
以下の例では、インスタンスメソッド内で使用した場合のみ、インスタンスオブジェクト
を指しました。
また、クラスメソッドを定義する際に用いるself
は、クラスオブジェクトを指しているため
self.メソッド名
のself
を直接クラス名で指定することもできます。
class Klass
# Klass
p self
# Klass
def (p self).class_method
puts "inner_class_method"
# Klass
p self
end
def instance_method
puts "inner_instance_method"
# <Klass:0x00007fa07e1a47c8>
p self
end
end
Klass.class_method
klass_instanse = Klass.new
klass_instanse.instance_method
クラスのネストなど
クラスを定義する際に、他のクラスにネストさせることができます。
定義の仕方として以下の2パターンがありますが、一部挙動が変わってきます。
# 直接中に記述する
class TopKlass
class Klass
end
end
## ------ ##
# ”::”を用いる
class TopKlass
end
class TopKlass::Klass
end
定義の仕方による挙動の違い
定数の参照
・直接中に記述
自身からトップレベル方向へ順に定数を参照していきます。
自身から近い順にから順に参照していき、最後にトップレベルを参照するという流れになります。
VALUE = "Top level"
class TopKlass
VALUE = "in TopKlass"
class InnerKlass
def self.put_value
puts VALUE
end
end
end
TopKlass::InnerKlass.put_value
# => in TopKlass
・ネームスペースを用いて記述
自身に定数がなければ、次にトップレベルを参照すし、そこから順に自身のクラス方向へ参照していきます。
VALUE = "Top level"
class TopKlass
VALUE = "in TopKlass"
end
class TopKlass::InnerKlass
def self.put_value
puts VALUE
end
end
TopKlass::InnerKlass.put_value
# => Top level
class,module のどちらにネストさせるのかを明確にする
・中に記述
各階層でclassかmoduleかを指定するため、別で定義したmoduleをclassとして指定するとエラーになります。
module TopKlass
end
class TopKlass
class InnerKlass
end
end
# => TopKlass is not a class (TypeError)
・ネームスペースを用いて記述
classかどうかを指定するのは、最後(一番右)に記述したもののみであるため、
それ以外はclassやmoduleの判断を柔軟に行ってくれます。
module TopKlass
end
class TopKlass::InnerKlass
end
# エラーにならない
ネスト元のオブジェクトがなかった時に例外を出すかどうか
・中に記述
以下の例の場合、TopKlassを別で定義していなかった場合、
新たにTopKlassを定義してくれるため例外は発生しません。
class TopKlass
class InnerKlass
end
end
・ネームスペースを用いて記述
以下の場合は、別でTopKlassを定義していなかった場合例外を出します。
新たにTopKlassを定義はしてくれません。
class TopKlass::InnerKlass
end
# => uninitialized constant TopKlass (NameError)