8

私はS4リファレンスクラスの大ファンです。ハイブリッドプログラミングスタイル(機能/値渡しとoop /リファレンス渡し;)が可能であり、柔軟性が劇的に向上します。

ただし、メソッドを介して特定のフィールド値を取得するように要求したときに、Rが環境/フレームをスキャンする方法に関して望ましくない動作に遭遇したと思います$field()ヘルプページを参照)。問題は、実際のローカル/ターゲット環境(S4参照クラスを構成する環境)で目的のフィールドが見つからない場合、つまり実行中のように、Rが環境/フレームを囲んでいるように見えることです(ヘルプをget(<objname>, inherits=TRUE)参照)ページ)。

実際の質問

Rにローカル/ターゲット環境だけを見てもらうために、私は次のようなことを考えていましたが、私が渡すことを可能にする引数$field(name="<fieldname>", inherits=FALSE)$field()ありません(これは途中で呼ばれていると思います)。これに対する回避策はありますか?...inherits=FALSEget()


コード例

詳細に興味のある方へ:動作を説明する小さなコード例を次に示します。

setRefClass("A", fields=list(a="character"))

x <- getRefClass("A")$new(a="a")

aクラスにフィールドがあるAため、ターゲット環境で検出され、値が返されます。

> x$field("a")
[1] "a"

参照クラスのフィールドではないが、ワークスペース/検索パス(この場合"lm")の他のオブジェクトの名前と同じ名前のフィールドにアクセスしようとすると、状況が異なります。

require("MASS")
> x$field("lm")

function (formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ...) 
{
    ret.x <- x
    ret.y <- y

    [omitted]

    if (!qr) 
        z$qr <- NULL
    z
}
<bytecode: 0x02e6b654>
<environment: namespace:stats>

現時点で私が期待することではありません。私見エラーまたは少なくとも警告ははるかに良いでしょう。$field()または、を介して他の関数に渡すことができる引数のメソッドを開き...ます。get()を呼び出すときに途中で呼び出されると推測している$field()ので、次のようなものが上記の動作の発生を防ぐ可能性があります。

x$field("digest", inherits=FALSE)

回避策:独自の提案

これでうまくいくはずですが、次のような新しいメソッドの指定を伴わない、よりエレガントなものがあるかもしれません$field()

setRefClass("A", fields=list(a="character"),
    methods=list(
        myField=function(name, ...) {
            # VALIDATE NAME //
            if (!name %in% names(getRefClass(class(.self))$fields())) {
                stop(paste0("Invalid field name: '", name, "'"))
            }
            # //
            .self$field(name=name)
        }
    )
)
x <- getRefClass("A")$new(a="a")

> x$myField("a")
[1] "a"
> x$myField("lm")
Error in x$myField("lm") : Invalid field name: 'lm'
4

1 に答える 1

1

デフォルトのfield()方法は、独自の方法に置き換えることができます。したがってinherits、囲んでいるフレームを避けるために引数を追加することは、単に既存のx$field定義を取得して追加することです...

setRefClass( Class="B",
             fields= list( a="character" ),
             methods= list(
               field = function(name, value, inherits=TRUE ) {
                 if( missing(value) ) {
                   get( name, envir=.self, inherits=inherits )
                 } else {
                   if( is.na( match( name, names( .refClassDef@fieldClasses ) ) ) ) {
                     stop(gettextf("%s is not a field in this class", sQuote(name)), domain = NA)
                   }
                   assign(name, value, envir = .self)
                 }
               }
             ),
)

または、少し並べ替えて、素敵なエラーメッセージを表示することもできます

setRefClass( Class="C",
             fields= list( a="character" ),
             methods= list(
               field = function(name, value, inherits=TRUE ) {
                if( is.na( match( name, names( .refClassDef@fieldClasses ) ) ) &&
                      ( !missing(value) || inherits==FALSE) ) {
                  stop(gettextf("%s is not a field in this class", sQuote(name)), domain = NA)
                }

                if( missing(value) ) {
                    get( name, envir=.self, inherits=inherits )
                } else {
                  assign(name, value, envir = .self)
                }
               }
             ),
)

独自のメソッドを定義してデフォルトを置き換えることができるため、必要なロジックをrefclassに実装できます。変数が継承を使用して取得されたが、モードがc( "expression"、 "name"、 "symbol"、 "function")に一致する場合はエラーであり、ローカルのrefClassフィールド名と直接一致しない場合は警告が表示される可能性があります。

于 2013-06-16T23:08:52.953 に答える