ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

パーフェクトRuby勉強日記 4章クラスとモジュール

クラスとモジュール。
クラスはJAVAC++で理解してるので問題なし。
モジュールははじめて知りましたが便利ですね。インスタンス化できないのがクラスと違う点。

4-1-2 インスタンスメソッド

str = 'abc'
#破壊的でないメソッド
p str.reverse()
p str

#破壊的なメソッド
p str.reverse!()#strは更新される
p str

自身を更新するのが破壊的メソッド、と。
メソッド名に!や?をつけられるのは好きです。

4-1-4 クラスメソッド

class Ruler
  attr_accessor :length
  class << self #特異クラス
    def pair
      [new,new]
    end

    def trio
      [new,new,new]
    end
  end
end

p Ruler.pair
p Ruler.trio

特異クラス、特異メソッドというのが今回結構頭を悩ませました。
クラスメソッド複数記述するときに便利な構文という理解。

なお特異メソッドはあるオブジェクトにのみ定義するメソッド

4-1-5 メソッドの呼び出し制限

class Processor
  def process
    protected_process = 3
  end
  
  def protected_process
    private_process
  end
  protected :protected_process #メソッド定義の直後にアクセス権限
  
  def private_process
    puts 'Done!'
  end
  private :private_process #メソッド定義の直後にアクセス権限
end

processor = Processor.new
p processor.process #->3

コメントでも書いてますがアクセス識別子をメソッド定義の直後に書くと。

4-1-6 クラスの継承

class Parent #スーパークラス
  def greet
    puts 'Hi!'
  end
end

class Child < Parent #サブクラス
end

p Child.superclass() #superclassを求めるメソッドか
child = Child.new() 
child.greet() #Hi!

記述が楽でいいですね。メソッドのオーバーライドもできます。

4-1-8 特異メソッド

class Foo
end

foo = Foo.new()
bar = Foo.new()

def bar.singleton_method
  puts 'Called'
end

bar.singleton_method
foo.singleton_method
#in `<main>': undefined method `singleton_method' for #<Foo:0x00000002798fe0> (NoMethodError)

#オブジェクト(bar)固有のメソッドを持つことができる
#これを特異メソッドと呼ぶ

Fooクラスのオブジェクトfoo、barのうちbarにだけメソッドを定義できる。すげー。

4-1-9 クラス変数とそのスコープ

class Parent
  @@val = 'foo' #クラス変数。クラス定義内で定義
  
  def self.say
    puts @@val
  end
end

class Child < Parent
  def say
    puts @@val
  end
end

Parent.say()
Child.say()
Child.new().say()

#クラス変数はそのクラスとサブクラス以外からは参照できない
child = Child.new()
@@val='yeah'

Parent.say #->yeah
#warning: class variable access from toplevel

クラス変数、クラスが持つ変数。staticみたいなイメージでよいかいな。
スコープはそのクラスと継承したクラスからしか呼べないとのことだったけど
警告は出るものの呼べるし、書き換えもできてるね…良いのだろうか

4-1-11 ネストした定数の参照

VALUE = 'toplevel'

class Foo
  VALUE = 'in foo class'
  def self.value
    p VALUE
  end
end

Foo.value() #->in foo class
#まずはクラス定数、定義されてなければ上位のネストの変数を探す。

Fooクラス内のVALUE定義をしなければ結果はtoplevelになる、と。

4-2-1 モジュールの特徴

module Sweet
  def self.lot
    %w(brownie apple-pie bavarois pudding).sample #Array#sampleは要素をランダムに返す
  end
end

p Sweet.lot()
p Sweet.lot()

モジュールは任意のメソッドを記述できるが、クラスと異なる点は
インスタンスを生成できない
・継承することはできない

self.で定義すれば特異メソッド
そんなことよりsampleってメソッド良いなあ いちいち標準クラスメソッドに関心するw

4-2-2 メソッドをクラスのインスタンスメソッドとして取り込む

module Greetable
  def greet_to(name)
    puts "Hello, #{name}. My name is #{self.class}."
  end
end

class AliceClass
  include Greetable
end

alice = AliceClass.new()
alice.greet_to('Bob') #->Hello, Bob. My name is AliceClass.

本命の使われ方なのかな?Greetableというモジュールをクラスでインクルードして使う。
クラス以外の部品化ってことですねー良いね

Mix-inというらしい。

4-2-3 メソッドをオブジェクトに取り込む

module Greetable
  def greet_to(name)
    puts "Hello,#{name}. I'm a #{self.class}."
  end
end

o = Object.new()
o.extend Greetable
#モジュールをオブジェクトの特異メソッドとして取り込む。extend。

o.greet_to 'World'
#->Hello,World. I'm a Object.

class Alice
  extend Greetable
end

Alice.greet_to('World')
#->Hello,World. I'm a Class.

#Aliceクラスではないのか

ここちょっと疑問で、.classってそのオブジェクトのクラスを返すメソッドで、
selfは自身なのでo.ObjectはObjectクラスであるのは良いんですが
AliceはAliceクラスじゃないのかなー
クラスクラスなのがよく分からない。

4-3-3 オブジェクトをコピーする

original = Object.new

p original.object_id #->20333180
original.freeze

#dupによるコピー
copy_dup = original.dup
p copy_dup.object_id #->20333080
p copy_dup.frozen?   #->false

#cloneによるコピー freezeされているかもコピー
copy_clone = original.clone
p copy_clone.object_id #->20332940
p copy_clone.frozen?   #->true

#配列のdupとcloneによるコピー
value = 'foo'
array = [value]

array_dup = array.dup
array_clone = array.clone

#全て同じオブジェクト
p value.object_id          #->20332800
p array_dup[0].object_id   #->20332800
p array_clone[0].object_id #->20332800
#なんで???

object_idが上の例と下の例で結果が異なる理由がさっぱり分かりません…

感想

モジュールは面白い!と思いました。
あとパーフェクトRuby、この本だけだと分からないことが多くて
その都度検索かけてて。それでも分からないものをここに乗せてるんだけど
Rubyってやっぱリファレンスを見ながら学んでいくのが正しいやりかたなんだろうなと今頃気づく。
RubyのことはRubyに聞けってことかー
===演算子、==演算子もクラスによって振る舞い違ったり
柔軟性が高い故に結構難しいと感じてます。

まだまだ手ごたえがない…