Ruby

たのしいruby class周り

一度rubyの文法を習得するために、たのrubyを読んだことはあるが、もう一度ちゃんとrubyに向き合うための前準備として、たのしいrubyを読み直してみる。

別のfileを取り込む

プログラムの一部を別の新しいプログラムの中で使いまわしたい場合、
require 使いたいライブラリのfile名(ここで、.rbは省略することができる。)
rubyにはたくさんの便利なライブラリがあるので、その都度それを呼ぶことができる。

クラスについて

クラスとインスタンス

hoge classのオブジェクトのことをhogeクラスのインスタンスを呼ぶ。rubyだと全てのオブジェクトは何かのクラスのインスタンスなので、必然的にインスタンス=オブジェクトみたいになっている。
例えば "foo"はStringクラスのインスタンスである。
classは型でインスタンスは型を元に作られたたい焼きに例えられる。
そのclassの新しオブジェクトを生成するときはclass名.newが一般的に用いられる。

initializeメソッド

newメソッドによってそのclassのオブジェクトが呼ばれると、最初に呼ばれるのが、initializeメソッド。initializeメソッドに渡される引数はnewの時に渡した引数。p126

インスタンス変数 p128

@で始まるインスタンス変数はそれぞれのインスタンス毎(オブジェクト)に値を保持する変数。同じインスタンスないだったら、メソッド定義を超える。p128がとてもわかりやすい。

アクセスメソッド p129

rubyではオブジェクトの外部から、インスタンス変数を直接参照したり、代入したりすることができないので、そのようにしたい場合にはそれ用のメソッドを定義する必要がある。例えば@nameに対して、参照や代入を行いたい場合は、

class HelloWorld
...
def name
 @name
end

def name=(value)
 @name = value
end
end

このようなメソッドを書いてあげることで、

bob.name => "Bob"
bob.name = "takahiro"

などの操作が可能になる。
これを一つ一つのインスタンス変数に対して行うのは非常にめんどくさいので、rubyが用意してくれているので、アクセスメソッド
attr_reader,attr_writer,attr_accessor
など。

self

インスタンスメソッド内でそのメソッドのレシーバ自身を参照するにはselfという変数を使う。ただ、省略しても暗黙にselfをレシーバとするので、意識することは少ない。ただ、name = みたいな感じで、イコール付きのメソッドの場合だとそのままローカル変数を定義する感じになってしまうので注意が必要。

クラスメソッド

クラスメソッドはクラス自信をレシーバとするメソッド。クラスメソッドはclass << クラス名 ... endの中に定義する。

class クラス名
 class << self
 end
end

という書き方もできる。
また、class <<の形式以外にも、

class HelloWorld
 def self.hello(name)
  puts "#{name}"
 end
end
HelloWorld.hello("john") #=> Jhon said hello.

このようにクラス定義内でクラス定義の中で、selfを用いて定義することもできる。

private

private内のメソッドの場合、レシーバを指定して呼び出すことができないので、インスタンスの外側から利用することができない。

特異クラス

クラスメソッドを用いると、任意のオブジェクトに、そのオブジェクトのみで使用できるメソッドを追加できる。

str1 = "Ruby"
str2 = "Ruby"

class << str1
 def hello
   "hello, #{self}"
 end
end

p str1.hello #=> "Hello Ruby"
p str2.hello #=> Error

module

クラスは実体(データ)と振る舞い(処理)を持ったものであるのに対して、moduleは
・インスタンスを持つことができない
・モジュールは継承できない
という点でclassと異なる。

extendメソッド

特異メソッドを一つ一つ追加する方法は上の特異クラスで説明した。extendを使うと、クラスを超えて、オブジェクト単位にモジュールの機能を追加することができる。

module Edition
 def edition(n)
   "#{self} 第#{n}版"
 end
end

str="楽しいruby"
str.extend(Edition) #=>ここでモジュールをオブジェクトにMix-inする
p str.edition(5) #=> 楽しいruby第5版

みたいな感じ。

クラスとMix-in

クラスはClassクラスのオブジェクトなので、クラスメソッドはクラスオブジェクトに対する、インスタンスメソッドであると言える。

めも p154 これは上のごちゃごちゃを一言でまとめてくれている 要注意 要復習

Rubyの全てのメソッド呼び出しは、レシーバとなるオブジェクトを伴って実行されます。

str.hello #=>みたいに クラスメソッドだろうがインスタンスメソッドだろうがレシーバが必ず存在している。

言い換えると
Rubyのメソッドは何らかのクラスに所属していて、レシーバとなるオブジェクトのインスタンスメソッドとして呼び出される。(特異メソッドでも)

str1 = "Ruby"
str2 = "Ruby"

class << str1
 def hello
   "hello, #{self}"
 end
end
p str1.hello #=> "Hello Ruby"

このとき、helloはstringを継承したstr1というクラス(クラスもオブジェクト)に属していて、Classクラスのインスタンスメソッドになっている。

その意味ではレシーバの種類の違いによって、インスタンスメソッドだったり、クラスメソッドだったりと呼ばれているだけで、実際にはおんなじ??
レシーバがオブジェクトの場合は色々と継承されてきたクラスの中の最下層オブジェクトってことで、特にオブジェクト臭が強いので、その真上にあるメソッドはインスタンスメソッド。
色々とまだ下にも継承している段階、つまりclassなのにそいつの真上にあるメソッドはクラスメソッド、ただ、実際にはclassもオブジェクトなので、本質的にはインスタンスメソッドということ。
わかった気になっている。明日読んだらわからなくなってる。解釈も学習段階によって異なると思うので、要修正。
Klassというクラスがあったとして、それを元に作られた、オブジェクト(インスタンス)が参照する、Klassクラス内に書かれているメソッドをインスタンス変数と呼ぶ。もし、作られたオブジェクトがclassだった場合はそれはインスタンスメソッドではなく、クラスメソッドと呼ばれる。(実際にはちょっと違うけど、この解釈が今の所ちょうど良さそう)

ポリフォーフィズム

これは、普段あんまり意識することがないから、とても気づきにくい。例えば同じようにto_sというメソッドを使って文字列化するのでも、intger型とstr型では内部的な処理が全然異なる。ただ、内部の状態が違ってもそのメソッドのしようとしていることが異ならないので、困らない。このように、同じ名前のメソッドが複数のオブジェクトに属することをポリモーフィズムと呼ぶ。

ダックタイピング

同じ操作を行えるならば、実際には異なるものであっても、その違いを気にする必要はない
実際は違うものであっても同じ名前のメソッドを用意することで、処理を共通化することができる。
同じ方法でアクセスできて、帰って来た値で実行したメソッドの中で不具合さえ起きなければ、同じ処理が行われるので、問題がない。
オブジェクト同士はメソッドを通じて情報をやり取りするので、その情報がオブジェクト内部でどのように扱われていようが知ったこっちゃない。要は何が返ってくるかが大事。