5

別の参照クラス内でカスタム参照クラスを使用したいのですが、このコードは失敗します:

nameClass <- setRefClass("nameClass", fields = list(first = "character",
                                                last = "character"),
                     methods = list(
                       initialize = function(char){
                         chunks <- strsplit(char,"\\.")
                         first <<- chunks[[1]][1]
                         last <<- chunks[[1]][2]
                       },
                       show = function(){
                         cat("Special Name Class \n:")
                         cat("First Name:")
                         methods::show(first)
                         cat("Last Name:")
                         methods::show(last)
                       }
                       ))
# this works fine
nameClass$new("tyler.durden")

クラスのフィールドを持つ 2 番目のクラスを追加しようとすると、nameClassこのクラスを開始できません。

personClass <- setRefClass("personClass", fields = list(fullname = "nameClass",
                                                    occupation = "character"),
                       methods = list(
                         initialize = function(Obj){
                           nm  <- deparse(substitute(Obj))
                           fullname <<- nameClass$new(nm)
                           occupation <<- Obj
                         }))

これは単に返されます:

 Error in strsplit(char, "\\.") : 
 argument "char" is missing, with no default

nameClass が S4 クラスであるソリューションを想像することはできましたが、少し読んで、S4 と参照クラスを混在させるのが少し怖くなりました。この特定の名前フィールドを単なる「文字」よりも正確に定義したい場合、何か不足していますか、それとも単純に S4 ​​クラスを使用する必要がありますか?

また、有望なタイトルのこのスレッドを見つけましたが、これが私の問題をどのように解決できるかわかりませんでした。

4

2 に答える 2

10

これは、S4 システムで一般的な問題のバリエーションです。継承が機能するには、new引数なしでの呼び出しが機能する必要があります。これは、基本クラスがインスタンス化され、派生クラスからの値が入力される継承の実装方法によるものです。基本クラスをインスタンス化するには、引数なしで作成する必要があります。あなたが問題を抱えていることは、

> nameClass()
Error in .Internal(strsplit(x, as.character(split), fixed, perl, useBytes)) : 
  'x' is missing

解決策は、初期化メソッドでデフォルトの引数を提供することです

initialize=function(char=charcter()) { <...> }

または、コンストラクターへの引数なしの呼び出しが機能するように(たとえば、missing(char)の本体でテストすることによって) 他の方法で調整します。initialize

おそらく、プログラミングのベスト プラクティスでは、initialize メソッドが...引数を取り、callSuper()その本体に持つようにすることで、派生クラスが基本クラス (フィールド割り当てなど) の機能を利用できるようにします。名前のない引数の不注意な一致による問題を回避するために、署名はおそらく次のようなテンプレートを中心に構築されるはずだと思います

initialize(..., char=character()) { callSuper(...) }

このスキームは、「空」の適切な定義に依存していますnameClass。以下はおそらく意見が多すぎて視点が変わってすぐには役に立ちませんが...nameClassデータフレームの「行」と考えたくなりますが、(Rはベクトルで最もうまく機能するため)それを考える方が良いです列を説明するように。これを念頭に置いて、「空の」nameClass の合理的な表現は、firstおよびlastフィールドがそれぞれ長さ 0 である場合です。

nameClass <- setRefClass("nameClass",
    fields = list(first = "character", last = "character"),
    methods = list(
      initialize = function(..., char=character()){
          if (length(char)) {
              names <- strsplit(char, ".", fixed=TRUE)
              .first <- vapply(names, "[[", character(1), 1)
              .last <- vapply(names, "[[", character(1), 2)
          } else {
              .first <- character()
              .last <- character()
          }
          callSuper(..., first=.first, last=.last)
      }, show = function(){
          .helper <- function(x)
              sprintf("%s%s", paste(sQuote(head(x)), collapse=", "),
                      if (length(x) > 6) ", ..." else "")
          cat("Special Name Class (n = ", length(first), ")\n", sep="")
          cat("First names:", .helper(first), "\n")
          cat("Last names:", .helper(last), "\n")
      }))

のようなテストケースで

> nameClass()
Special Name Class (n = 0)
First names:  
Last names:  
> nameClass(char="Paul.Simon")
Special Name Class (n = 1)
First names: 'Paul' 
Last names: 'Simon' 
> nameClass(char=c("Paul.Simon", "Frank.Sinatra"))
Special Name Class (n = 2)
First names: 'Paul', 'Frank' 
Last names: 'Simon', 'Sinatra' 
> nameClass(char=paste(LETTERS, letters, sep="."))
Special Name Class (n = 26)
First names: 'A', 'B', 'C', 'D', 'E', 'F', ... 
Last names: 'a', 'b', 'c', 'd', 'e', 'f', ... 

派生クラスは次のように定義できます。

personClass <- setRefClass("personClass",
    fields = list(fullname = "nameClass", occupation = "character"),
    methods = list(
      initialize = function(..., fullname=nameClass(),
                            occupation=character()) {
          callSuper(..., fullname=fullname, occupation=occupation)
      }))

のようなテストケースで

personClass()
personClass(fullname=nameClass())
personClass(fullname=nameClass(), occupation=character())
personClass(fullname=nameClass(char="some.one"), occupation="job")
于 2013-09-19T12:36:58.743 に答える
1

これは、「nameClass」のデフォルトのコンストラクターがないためのようです。

nameClass$new()
Error in strsplit(char, "\\.") : 
  argument "char" is missing, with no default

nameClass を次のように変更すると:

nameClass <- setRefClass("nameClass", fields = list(first = "character",
                                                    last = "character"),
                         methods = list(
                           initialize = function(s = NULL) {
                             if (!is.null(s) && nzchar(s)) {
                               chunks <- strsplit(s,"\\.")
                               first <<- chunks[[1]][1]
                               last <<- chunks[[1]][2]
                             }
                           },
                           show = function(){
                             cat("Special Name Class \n:")
                             cat("First Name:")
                             methods::show(first)
                             cat("Last Name:")
                             methods::show(last)
                           }
                         ))

それで:

nameClass$new()
Special Name Class 
:First Name:character(0)
Last Name:character(0)

personClass が機能するようになりました (ただし、initialize メソッドは非常に奇妙です)。

personClass$new("tyler.durden")
Reference class object of class "personClass"
Field "fullname":
Special Name Class 
:First Name:[1] "\"tyler"
Last Name:[1] "durden\""
Field "occupation":
[1] "tyler.durden"
于 2013-09-19T13:01:26.630 に答える