8

class_eval方法とinstance_eval動作に違いはありますdefか?Insideclass_evalブロックdefは、それ自体をクラス化するメソッド(つまり、インスタンスメソッド)をinstance_eval def定義し、insideは、クラスの固有クラス(つまり、クラスメソッド)にメソッドを定義します。AFAIKの他のすべての機能は、どちらの場合も同じように機能します(たとえば、、、、define_method定数attr_accessorclass << self; end定義)。それは本当ですか?

答えはdefundefであり、とaliasのコンテキストが異なります。class_evalinstance_eval

4

2 に答える 2

16

短編小説:

  • Object.instance_eval &blockセット:
  • Object.class_eval &blockセット:
    • selfObject
    • 「現在のクラス」からObject

「現在のクラス」は、定数およびクラス変数のルックアップだけでなく、、、にもdef使用undefされます。alias


それでは、実装の詳細を見てみましょう。

Cでの実装方法module_evalと実装方法は次のとおりです。instance_eval

VALUE rb_mod_module_eval(int argc, VALUE *argv, VALUE mod) {
    return specific_eval(argc, argv, mod, mod);
}

VALUE rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) {
    VALUE klass;
    if (SPECIAL_CONST_P(self)) { klass = Qnil; }
    else { klass = rb_singleton_class(self); }
    return specific_eval(argc, argv, klass, self);
}

どちらも、を呼び出します。これは、、、、およびspecific_evalの引数を取りint argcます。VALUE *argvVALUE klassVALUE self

ご了承ください:

  • module_evalModuleまたはClassインスタンスをとの両方として渡しますklass self
  • instance_evalオブジェクトのシングルトンクラスを次のように渡しますklass

ブロックが与えられた場合、は、specific_evalを呼び出しますyield_under。これは、次の引数を取ります:VALUE underVALUE selfおよびVALUE values

if (rb_block_given_p()) {
    rb_check_arity(argc, 0, 0);
    return yield_under(klass, self, Qundef);
}

には2つの重要な行がありますyield_under

  1. block.self = self;

    これselfにより、ブロックのがレシーバーに設定されます。

  2. cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);

    は、、、、および定数とクラス変数のルックアップに 使用される「現在のクラス」を指定crefするリンクリストです。defundefalias

    その行は基本的にをに設定crefunderます。

    ついに:

    • から呼び出されると、module_evalまたはインスタンス になります。underClassModule

    • から呼び出されると、のinstance_evalシングルトンクラスになり ます。underself

于 2012-04-24T21:11:22.690 に答える
0

instance_evalインスタンスのインスタンス変数に直接アクセスし、インスタンスへのself参照として使用できます。

于 2012-04-24T18:23:22.273 に答える