クラスのインスタンス変数について
Post on 30-Jun-2015
5.839 Views
Preview:
DESCRIPTION
TRANSCRIPT
クラスのインスタンス変数について
2011/1/8
cuzic
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
22自己紹介
cuzic といいますきゅーじっく と読みます
Ruby 暦は かれこれもう10年くらいKindle 向けサーバサイドアプリを作成中
takibi <http://www.github.com/cuzic/takibi>WEB 上の記事の Scraping ⇒ epub 作成を自動実行4階層モデル( model 、 crawler 、 parser 、 formatter )安価な 共有 WEB ホスティングで動作できるよう工夫
デーモンの常駐不要。 Cron で定期的に実行。
多数の日本語の WEB 記事に対応JBpress 、 Livedoor Blogos 、日経ビジネスオンライン、 etc
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
33Ruby の変数の種類と、インスタンス変数
Ruby の変数には下記の種類があるローカル変数 ・・・ 英小文字から始まるインスタンス変数 ・・・ @ から始まるクラス変数 ・・・ @@ から始まるグローバル変数 ・・・ $ から始まるその他 (擬似変数、 定数)
インスタンス変数とはあるオブジェクトに所属する変数同一の 「 @value 」という変数名でも所属するオブジェクトが異なれば、異なるオブジェクトを参照する。
class A def initialize @value = “” end
def get return @value endend
a = A.newb = A.newp a.get.object_idp b.get.object_id(参考) クラス変数との違い
同一クラスのインスタンスメソッド、クラスメソッド、クラス定義内は クラス変数名が同一であれば同一のオブジェクトを参照している。
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
44クラスのインスタンス変数とは
Ruby はすべてがオブジェクトクラスもオブジェクト ( Class クラスのインスタンス) ⇒ クラスも通常のオブジェクトと同様、所属する インスタンス変数を持つことができる
クラスのインスタンス変数の利用@value の初期化
クラス定義内で、クラスのインスタンス変数を初期化
@value2 の初期化クラスメソッド(=クラスの特異メソッド)の中でクラスのインスタンス変数を定義
@value 、 @value2 の参照クラスメソッドから参照している
class A @value = Object.new
def self.value return @value end
def self.set @value2 = 2 end
def self.value2 @value2 endend
v = A.valueA.setv2 = A.value2
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
55クラスのインタンス変数の特徴
サブクラスから参照できないクラス B はクラス A とは異なるオブジェクトであるため、クラス B からクラス A のインスタンス変数は参照できない。
インスタンスメソッドから参照できないクラス A と クラス A のインスタンスは異なるオブジェクト。異なるオブジェクトであるため、インスタンスメソッドからクラスのインタンス変数にはアクセスできない
class A @value = []
def self.value return @value end
def instance_method return @value endend
class B<A p @value #=> nilend
p A.value #=> []p B.value #=> nilp A.new.instance_method #=> nil
(参考) クラス変数との違いクラス変数であれば、サブクラスやインスタンスメソッドから参照できる。
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
クラスのインスタンス変数の長所 66
class Base def self.civar= val @civar = val end
def self.civar @civar end
def civar= val self.class.civar = val end
def civar self.class.civar endend
クラスメソッドを定義することで、サブクラスで参照可能になる
インスタンスメソッドを定義することで、インスタンスメソッド内で参照可能になる
クラスのインスタンス変数は下位クラスから直接参照することができないため、参照性を制御しやすい
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
継承があった場合 77
class Base def self.civar= val @civar = val end
def self.civar @civar endend
class Subclass < Baseend
Base.civar = 1
p Subclass.civar #=> nil
Subclass.civar = 2
p Base.civar #=> 1
この行で 1 と表示させたいときは、
後述の class_attribute を利用する
① : Subclass.civar の呼び出し
② : 存在しないので、 Base.civar の呼び出し
③ : インスタンス変数 @civar の 値を返す。このとき self は Subclass のため @civar は未定義
サブクラスはスーパークラスと異なるオブジェクトのため、同じ名前のインスタンス変数でも異なるオブジェクトを参照する
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
(参考) クラス変数の参照性
サブクラスから参照可能
インスタンスメソッドから参照可能
サブクラスでの変更がグローバルに影響が及ぶ
クラスのインスタンス変数
×(アクセサメソッドが必要)
×(アクセサメソッドが
必要)
×(そもそも参照不可)
クラス変数 ○ ○ ○
ActiveSupport のclass_attribute(後述)
○(アクセサメソッド)
○(アクセサメソッド)(オプションで設定可
能)
×(破壊的変更を
行った場合を除く)
(参考) 定数 ○ ○
×(サブクラスでの定数
への代入文は新定数の定義となる)
88
Ruby のクラス変数は参照可能な範囲が限定されたグローバル変数
変更が全継承階層の同一名のクラス変数に影響する
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
クラスのインスタンス変数の使用例 99
class Foo extend Exception2MessageMapper def_e2message ExsitingExceptionClass, “message …” def_exception :NewExceptionClass, “message …”end
Foo.Fail NewExceptionClass, arg …
Foo.Fail ExistingExceptionClass, arg …
Exception2MessageMapper例外クラスに特定のエラーメッセージ用
フォーマットを関連付けるためのライブラリメッセージフォーマットを Module のインスタンス変数で保持
インスタンス変数のため、変数名重複の心配なしクラス変数の場合は、変数名重複の場合、誤動作が生じる。
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
1010スーパークラスの値をデフォルト値にしたい!
ActiveSupport の class_attribute を使うと、継承時に、デフォルト値としてスーパークラスの値を利用可能
require “rubygems”require “active_support/core_ext/class”
class Base class_attribute :settingend
class Subclass < Baseend
Base.setting = truep Subclass.setting #=> trueSubclass.setting = false p Subclass.setting #=> false
P Base.setting #=> true
class Base def self.setting= val class << self self end.class_eval do define_method :setting do val end end endend
class_eval
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
1111class_attribute を利用した例(1)
ActiveSupport::Rescuable例外処理を rescue_from で体系的に行うためのモジュール
例外処理のコールバックをクラスのインスタンス変数に格納継承したとき、デフォルトで親のコールバックを利用するように、前のスライドの class_attribute を利用
ActiveSupport::Rescuable のように、クラスに対して新たな機能を付加するモジュールを作成するときは、クラス変数が役立つときがある。
class ApplicationController < ActionController::Base
# include ActiveSupport::Rescuable # すでに include している
rescue_from ActiveRecord::RecordInvalid do |exception| render :action => (exception.record.new_record? ? :new : :edit) endend
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
class_attribute を利用した例(2)
ActiveRecord の場合大量のコールバックが利用可能
コールバックは主にクラスのインスタンス変数に保存
コールバックを管理するObserver もクラスのインスタンス変数に保存
1212コールバック タイミング
after_create 新規作成し、保存したあと
after_destroy 削除したあと
after_save 新規作成、更新したあと
after_update 更新したあと
after_validation バリデーションしたあと
before_create 新規作成する前
before_destroy 削除する前
before_save 新規作成、更新する前
before_update 更新する前
before_validation バリデーションする前
クラス内で共通だが、継承ツリー全体での共有はしたくない
設定はクラスのインスタンス変数を用いるとうまく実装できる
Ruby 勉強会 第48回発表資料 「クラスのインスタンス変数について」
まとめ
Ruby ではクラスもオブジェクトクラスもインスタンス変数を持つことができる
クラスのインスタンス変数は制御しやすいアクセサメソッドの定義によって制御可能クラス変数だと、サブクラスからでも変更可能
上位クラスも影響を受ける
Module 内でだけ有効な private なクラス変数としてModule 自身のインスタンス変数を使うこともできる継承したとき、スーパークラスの値をデフォルト値として使いたいときは、 class_attribute を用いる
1313
top related