简体   繁体   中英

R: how to define multiple constructors for an R6 class?

I am currently working on a project where I need to build an R6 class in R that can be initialized in more than one way. I am wondering what the best way is to go about it. Is it possible to overload the $new() function? Or do I need to define a helper function?

As a motivating example: I would like to have two constructors for an R6 class MyClass with a field names that can be initialized using either using vector variable_names or a integer n_variables (in which case it initializes a default vector of names).

The functionality should work like this:

#define the class (only has a constructor that accepts a vector of names)
myClass <- R6Class("myClass",
                   public = list(
                     names = NA,
                     initialize = function(names) {
                       if (!missing(names)) self$names <- names
                     })
)

#create a test object using a vector of names
variable_names = c("x","y")
a = myClass$new(variable_names)
a$names
#> [1] "x y"

#everything after here does not actually work (just to illustrate functionality)
n_variables = 2;
b = myClass$new(n_variables)
b$names
#> [1] "v1 v2"

I took a look through the Introductory vignette, but there doesn't seem to be a clear way to do this.

Ideally, I am looking for a solution that does not force me to name the arguments (ie so I do not have to do something like myClass$new(names=variable_names) ) and that lets me easily check that the inputs are valid.

Possible way is to use dot-dot-dot (ellipsis) argument for constructor which allows you to pass arbitrary number of arguments into function. After that you have to convert the "..." to the list and parse input arguments.


For example suppose that we want to overload the constructor by arity.

myClass <- R6Class("myClass",
   public = list(
      name = NA,
      age = NA,
      favouriteFood = NA,
      # Constructor overloaded by arity
      initialize = function(...) {
         arguments <- list(...)
         switch(nargs(),
            # one input argument
            {self$name <- arguments[[1]]},
            # two input arguments
            {self$name <- arguments[[1]]
            self$age <- arguments[[2]]},
            # three input arguments
            {self$name <- arguments[[1]]
            self$age <- arguments[[2]]
            self$favouriteFood <- arguments[[3]]}
         )
         print(self)
      })
)

Calling the constructor now gives us

> a = myClass$new("john")
<myClass>
  Public:
    age: NA
    clone: function (deep = FALSE) 
    favouriteFood: NA
    initialize: function (...) 
    name: john
> a = myClass$new("john",35)
<myClass>
  Public:
    age: 35
    clone: function (deep = FALSE) 
    favouriteFood: NA
    initialize: function (...) 
    name: john
> a = myClass$new("john",35,"pasta")
<myClass>
  Public:
    age: 35
    clone: function (deep = FALSE) 
    favouriteFood: pasta
    initialize: function (...) 
    name: john

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM