2016-02-03 5 views
11

誰かがこの動作を私に説明できますか?複数の環境を割り当てる

私は/ a/b/cが同じように作成された変数と非常に異なる環境であると予想しましたか?

しかし、3つの環境が地球環境で表示されますが、1つの環境上のアクションはすべての環境にプッシュされます。

+2

環境の参照セマンティクスについては、Hadley http://adv-r.had.co.nz/Environments.htmlを参照してください。 - > "スコープの強化と同様に、環境は参照セマンティクスを持つため、有用なデータ構造です。Rのほとんどのオブジェクトとは異なり、環境を変更するとコピーは作成されません。 – cryo111

答えて

13

免責事項:この答えはR内のすべてのオブジェクトに近いため一般的なタイプであるS-式と全くSFWではないかもしれないがSEXP(うん、S-表現省略されている、あなたが思ったところ、ハイフンではありません)。今度はSALT 'N' PEPAが歌いました:SEXPについて話しましょう!


TL; DR:環境がそれに保存されているだけで、ポインタを複製し、まだ同じオブジェクトをターゲットに、それをアクセスするための変数をコピーし、ポインタとして親環境です。私はいくつかの根本的な原因に掘りでした


、主な理由は、それはそれの親環境に保存されているか、環境、または実際には何かということです。 (私はここにショートカットを取ったリターンbuiltin.cに私たちをもたらすdo_newenv検索

{"new.env", do_newenv, 0, 11,  3,  {PP_FUNCALL, PREC_FN, 0}}, 

が、のではなく、これを維持してみましょう:

> new.env 
function (hash = TRUE, parent = parent.frame(), size = 29L) 
.Internal(new.env(hash, parent, size)) 
<bytecode: 0x0000000005972428> 
<environment: namespace:base> 

names.cで、ソースコードに移動するには、[OK]、時間:さんはnew.envを見てみましょうあまりにも)長い:

ans = NewEnvironment(R_NilValue, R_NilValue, enclos); 

このNewEnvironmenthere in memory.c定義され、COMMその上エントは私たちに何が起こっているかについての手掛かりを与える:

を 値を持つ「名前リスト」のタグで指定した変数名を対
によって得られたフレームで「ロー」を拡張することで、環境を作成します。 「valuelist」の要素によって与えられる。

自体のコードが従うことはそれほど簡単ではありません。

void gsetVar(SEXP symbol, SEXP value, SEXP rho) 
{ 
    if (FRAME_IS_LOCKED(rho)) { 
    if(SYMVALUE(symbol) == R_UnboundValue) 
     error(_("cannot add binding of '%s' to the base environment"), 
      CHAR(PRINTNAME(symbol))); 
    } 
#ifdef USE_GLOBAL_CACHE 
    R_FlushGlobalCache(symbol); 
#endif 
    SET_SYMBOL_BINDING_VALUE(symbol, value); 
} 
gsetVarによる地球環境での変数定義(exempleが読者の心の健全性のために選びだし)に比べ

SEXP NewEnvironment(SEXP namelist, SEXP valuelist, SEXP rho) 
{ 
    SEXP v, n, newrho; 

    if (FORCE_GC || NO_FREE_NODES()) { 
    PROTECT(namelist); 
    PROTECT(valuelist); 
    PROTECT(rho); 
    R_gc_internal(0); 
    UNPROTECT(3); 
    if (NO_FREE_NODES()) 
     mem_err_cons(); 
    } 
    GET_FREE_NODE(newrho); 
    newrho->sxpinfo = UnmarkedNodeTemplate.sxpinfo; 
    INIT_REFCNT(newrho); 
    TYPEOF(newrho) = ENVSXP; 
    FRAME(newrho) = valuelist; 
    ENCLOS(newrho) = CHK(rho); 
    HASHTAB(newrho) = R_NilValue; 
    ATTRIB(newrho) = R_NilValue; 

    v = CHK(valuelist); 
    n = CHK(namelist); 
    while (v != R_NilValue && n != R_NilValue) { 
    SET_TAG(v, TAG(n)); 
    v = CDR(v); 
    n = CDR(n); 
    } 
    return (newrho); 
} 

親環境からアクセス可能な "値"は親環境上のGET_FREE_NODEによって与えられる新しい環境アドレスです(私はここではわかりませんが、正しいpが見つかりませんでした老化)。

したがって、<-は、x <- valueと定義されています。ポインタをコピーしています。複数の独立変数があり、すべてが同じオブジェクトを指しています。

任意の参照を使用してオブジェクトを更新すると、メモリ内に存在する唯一のオブジェクトが更新されます。様々なliterratureに応じてS-発現のための

SEXPスタンドは、主に感謝@BrodieG

  • A blog post about R's C interface
  • おかげ@Alexis_laz

    • R language defintion C.コメントから

      でポインタであります本当の根本的な原因をより詳細に把握するように強制する

  • +2

    だから、もし私が要約するならば。これは、 'new.env()'が環境へのポインタを返すためです。本質的に、 'a <-b <-c <-new.env()'をチェーンすると、 'b'と' cそれゆえ、1つのアクションは自動的に他のアクションにプッシュされます(他のアクションは最初のものを指しているためです)。 @Brandonは正確に –

    +2

    です。 new.envのドキュメントでは、それを明確に述べていません。 – Tensibai

    +2

    * SEXP *は何を表していますか?私をオフィスから追い出したグーグル、ほとんど。 –

    7

    new.env()は1回だけ呼び出され、新しい環境が1つだけ作成されます。同じnew.env()コールへのすべての割り当てをチェーンしているため、それらはすべて同じ環境になります。したがって、1つに割り当てると、すべてに割り当てられます。

    a <- b <- c <- new.env() 
    
    a 
    # <environment: 0x49c1ed8> 
    b 
    # <environment: 0x49c1ed8> 
    c 
    # <environment: 0x49c1ed8> 
    

    あなたがそれらを別の環境になりたい場合は、(すなわちnew.env()に3つの別々の呼び出しを使用)の割り当てをチェーンしないでください。完全のために

    、中Tensibaiさんのコメントをもたらす - これは、コードのあなたのライン<-の副作用がよりobvisouly new.env() 3回を呼び出しますが、3にそれを参照しない(a <- new.env(); b <- a; c <- aと同じである

    変数名)

    +1

    同じ環境の3つのコピーが1つのワークスペースにあるのはなぜですか?私はこの振る舞いのユースケースを理解することに興味があります。私の理解では、環境は 'lists()'のように設計されていましたが、この動作は少し直感的ではありません。 –

    +6

    @BrandonBertelsenこれは '< - 'の副作用で、あなたのコード行は 'a < - new.env();と同じです。 b < - a; c < - a'(これはobveouly new.env()を3回呼び出すのではなく、3つの変数名を参照してください) – Tensibai

    +0

    上記のように、これは割り当てともっと関係していると思います。 'a < - b < - c < - 3'は間違いなく便利なこともありますが、実際には環境にはあまり役に立ちません。 –

    関連する問題