如何使 Ops 方法在非基础的两个对象之间兼容 class
How to make Ops method compatible between two objects of a non base class
假设我有一个 class“我的”,当它被添加到具有单位的对象(即来自 units
包)时,我想触发某些行为:
library(units)
my1 = structure(2, class="my")
Ops.my <- function(e1, e2=NULL) {
ok <-
switch(
.Generic,
`-` = ,
`*` = ,
`+` = ,
'<=' = TRUE,
FALSE
)
if (!ok) {
stop(gettextf("%s not meaningful", sQuote(.Generic)))
}
get(.Generic)(as.integer(e1), as.integer(e2))
}
my1+set_units(5,nm)
目前,它给我以下警告:
Warning message:
Incompatible methods ("Ops.my", "Ops.units") for "+"
但我实际上想以某种方式处理“我的”和“单位”的加法,我该怎么做?
我试过 Ops.my.units <-
之类的东西,但它似乎不起作用。
Ops
似乎没有办法做到这一点。来自文档:
The classes of both arguments are considered in dispatching any member of this group. For each argument its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about ‘incompatible methods’
这可能是一件好事。 object-oriented 系统在像 R 这样的 non-compiled 语言中的部分好处是它有助于保持类型安全。这可以防止您不小心将苹果添加到橙子中,正如我们在以下示例中看到的那样:
apples <- structure(2, class = "apples")
oranges <- structure(2, class = "oranges")
Ops.apples <- function(e1, e2) {
value <- do.call(.Generic, list(as.integer(e1), as.integer(e2)))
class(value) <- "apples"
value
}
Ops.oranges <- function(e1, e2) {
value <- do.call(.Generic, list(as.integer(e1), as.integer(e2)))
class(value) <- "oranges"
value
}
apples + apples
#> [1] 4
#> attr(,"class")
#> [1] "apples"
oranges + oranges
#> [1] 4
#> attr(,"class")
#> [1] "oranges"
apples + oranges
#> [1] 4
#> attr(,"class")
#> [1] "apples"
#> Warning message:
#> Incompatible methods ("Ops.apples", "Ops.oranges") for "+"
你可以看到,即使在这里,我们也可以忽略警告。
suppressWarnings(apples + oranges)
#> [1] 4
#> attr(,"class")
#> [1] "apples"
但希望您能明白为什么这可能不太好 - 我们添加了 2 个苹果和 2 个橙子,并返回了 4 个苹果。
在整个 R 及其扩展包中,有许多 type-conversion 函数,例如 as.integer
、as.numeric
、as.logical
、as.character
、as.difftime
等。这些允许在类型之间转换和对不同类型执行操作时进行一些控制。
做这种事情的“正确”方法是专门将一种对象类型转换为另一种对象类型以执行操作:
as.my <- function(x) UseMethod("as.my")
as.my.default <- function(x) {
value <- as.integer(x)
class(value) <- 'my'
value
}
my1 + as.my(set_units(5,nm))
#> [1] 7
假设我有一个 class“我的”,当它被添加到具有单位的对象(即来自 units
包)时,我想触发某些行为:
library(units)
my1 = structure(2, class="my")
Ops.my <- function(e1, e2=NULL) {
ok <-
switch(
.Generic,
`-` = ,
`*` = ,
`+` = ,
'<=' = TRUE,
FALSE
)
if (!ok) {
stop(gettextf("%s not meaningful", sQuote(.Generic)))
}
get(.Generic)(as.integer(e1), as.integer(e2))
}
my1+set_units(5,nm)
目前,它给我以下警告:
Warning message:
Incompatible methods ("Ops.my", "Ops.units") for "+"
但我实际上想以某种方式处理“我的”和“单位”的加法,我该怎么做?
我试过 Ops.my.units <-
之类的东西,但它似乎不起作用。
Ops
似乎没有办法做到这一点。来自文档:
The classes of both arguments are considered in dispatching any member of this group. For each argument its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about ‘incompatible methods’
这可能是一件好事。 object-oriented 系统在像 R 这样的 non-compiled 语言中的部分好处是它有助于保持类型安全。这可以防止您不小心将苹果添加到橙子中,正如我们在以下示例中看到的那样:
apples <- structure(2, class = "apples")
oranges <- structure(2, class = "oranges")
Ops.apples <- function(e1, e2) {
value <- do.call(.Generic, list(as.integer(e1), as.integer(e2)))
class(value) <- "apples"
value
}
Ops.oranges <- function(e1, e2) {
value <- do.call(.Generic, list(as.integer(e1), as.integer(e2)))
class(value) <- "oranges"
value
}
apples + apples
#> [1] 4
#> attr(,"class")
#> [1] "apples"
oranges + oranges
#> [1] 4
#> attr(,"class")
#> [1] "oranges"
apples + oranges
#> [1] 4
#> attr(,"class")
#> [1] "apples"
#> Warning message:
#> Incompatible methods ("Ops.apples", "Ops.oranges") for "+"
你可以看到,即使在这里,我们也可以忽略警告。
suppressWarnings(apples + oranges)
#> [1] 4
#> attr(,"class")
#> [1] "apples"
但希望您能明白为什么这可能不太好 - 我们添加了 2 个苹果和 2 个橙子,并返回了 4 个苹果。
在整个 R 及其扩展包中,有许多 type-conversion 函数,例如 as.integer
、as.numeric
、as.logical
、as.character
、as.difftime
等。这些允许在类型之间转换和对不同类型执行操作时进行一些控制。
做这种事情的“正确”方法是专门将一种对象类型转换为另一种对象类型以执行操作:
as.my <- function(x) UseMethod("as.my")
as.my.default <- function(x) {
value <- as.integer(x)
class(value) <- 'my'
value
}
my1 + as.my(set_units(5,nm))
#> [1] 7