在S4类对象中实现基本算术

时间:2017-12-12 14:43:18

标签: r class s4

我正在以下列方式创建 money 类的S4对象:

# Create class ------------------------------------------------------------

# Create S4 class object holding money and export to generator function
setClass(Class = "money",
         slots = list(currency = "character",
                      value = "numeric")) -> money

我稍后定义 show 方法:

# Methods -----------------------------------------------------------------

# Create show method
setMethod("show",
          "money",
          function(object) {
              cat(switch(object@currency,
                         GBP = intToUtf8(163)),
                  format(
                      x = round(object@value, 2),
                      trim = TRUE,
                      big.mark = ",",
                      big.interval = 3
                  ),
                  sep = "")
          })

预览

到目前为止它按照承诺的方式运作:

# Create test object
tst_fig <- new(Class = "money",
               value = 1e6,
               currency = "GBP")

# Show the object
tst_fig
# £1,000,000

问题

我想在该对象上启用基本算术:

>> tst_fig + 1e6
Error in tst_fig + 1000000 : non-numeric argument to binary operator

期望的结果

> tst_fig + 1e6
# £2,000,000

尝试

当然这不起作用:

>> setMethod("+",
...           "money",
...           function(object, x) {
...               object@value + x
...           })
Error in conformMethod(signature, mnames, fnames, f, fdef, definition) : 
  in method for ‘+’ with signature ‘e1="money"’: formal arguments (e1 = "money", e2 = "money") omitted in the method definition cannot be in the signature

旁注

excellent answer在S3中实施金钱等级时提供了类似的@Roland;在这个问题的上下文中,我有兴趣创建S4类,除了好奇之外没有任何特定原因会以类似的方式运行。关键要求是该对象上的 isS4() 返回 TRUE

我的意思是类似的方式

它打印得格式化得很好,但允许所有操作都能用普通数字进行操作。

1 个答案:

答案 0 :(得分:3)

我在自己的问题here中遇到过如何做到这一点。我通常使用setMethod('Arith')方法,因为当您打算实现多个操作时它更简洁。如果您搜索文档?Arith,您会看到它列出了不同的操作以及其他S4组泛型。

由于错误提示您需要为e1方法定义e2Arith。在您的具体情况下,以下工作。

注意 - 要获得所需的输出(即money类对象),您需要创建一个新的money对象。

setMethod("+", 
    c(e1="money", e2="numeric"), 
    function(e1, e2){
        new(Class = "money", value = e1@value + e2, currency = e1@currency)
    }
)

tst_fig + 1e6
[1] £2e+06

但是,正如我所说,您可能希望使用.Generic更通用,更简洁的版本来解释您正在使用的Arith方法。

setMethod("Arith", 
    c(e1="money", e2="numeric"),
    function(e1, e2)
    {
        op = .Generic[[1]]
        switch(op,
            `+` = return(new(Class = "money", value = e1@value + e2, currency = e1@currency))
        )
    }
)