S3 中的单个重载运算符的多次分派(在 R 中)
Multiple dispatches on an a single overloaded operator in S3 (in R)
我想在使用 S3 时重载 R 中的“*”(乘法运算符)class。
我看到 * 在系统中已经是通用的,但我 也 想要它 "generic2",即在第二个参数上调度。
用例如下:假设我的class被称为"Struct"。我希望能够允许所有这三种情况
Struct * Struct
Struct * Number
Number * Struct
但是我发现如果我允许对第二个参数进行调度,第一个参数的(已经存在的)调度将被覆盖!
有什么方法可以在 S3 中做到这一点吗?
# "generic1" already exists for '*'
'*' <- function(x,y){
UseMethod('*2',y)
}
'*.Struct'<-function(x,y){
# must both be structs, so dispatch 'normally' if not
"times(1)"
}
`*2.Struct`<-function(x,y){
# must both be structs, so dispatch 'normally' if not
"times(2)"
}
给我...
> struct1 * struct2
[1] "times(2)"
> 2 * struct2
[1] "times(2)"
> struct1 * 2
Error in UseMethod("*2", y) :
no applicable method for '*2' applied to an object of class "c('double', 'numeric')"
>
如果我用这个,而不是
'*' <- function(x,y){ UseMethod('*',x)}
然后对第一个参数的调度起作用,相反的情况发生:
> struct1 * 2
[1] "times(1)"
> struct1 * struct2
[1] "times(1)"
> 2* struct1
Error in UseMethod("*", x) :
no applicable method for '*' applied to an object of class "c('double', 'numeric')"
>
看来他们肯定是在互相覆盖。
关于两者如何和平而富有成效地共存有什么想法吗?
你可以检查函数内部:
'*.Struct'<-function(x,y){
if(inherits(x,'Struct') && inherits(y,'Struct'))
"Struct*Struct"
else if(inherits(y,'Struct'))
"N*Struct"
else
"Struct*N"
}
# N.B.: you don't need to redefine `*`,`*2.Struct` etc
例如:
struct1=structure(5,class='Struct')
struct2=structure(3,class='Struct')
struct1*struct2
# [1] "Struct*Struct"
struct1*2
# [1] "Struct*N"
3*struct2
# [1] "N*Struct"
如前所述 here 调度对两个参数都起作用,规则如下:
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’: in that case or if no method is
found for either argument the internal method is used.
因此,例如,由于还有一个 *.difftime
方法定义,这些情况将给出带有警告的奇怪结果:
difftimeObj <- Sys.time()-Sys.time()
struct1*difftimeObj
# [1] 0
# attr(,"units")
# [1] "secs"
# attr(,"class")
# [1] "Struct"
# Warning message:
# Incompatible methods ("*.Struct", "*.difftime") for "*"
difftimeObj*struct2
# Time difference of 0 secs
# Warning message:
# Incompatible methods ("*.difftime", "*.Struct") for "*"
而这些反而有效:
struct1*unclass(difftimeObj)
# [1] "Struct*N"
unclass(difftimeObj)*struct2
# [1] "N*Struct"
# skipping dispatching
`*.Struct`(struct1, difftimeObj)
# [1] "Struct*N"
`*.Struct`(difftimeObj, struct2)
# [1] "N*Struct"
我想在使用 S3 时重载 R 中的“*”(乘法运算符)class。
我看到 * 在系统中已经是通用的,但我 也 想要它 "generic2",即在第二个参数上调度。
用例如下:假设我的class被称为"Struct"。我希望能够允许所有这三种情况
Struct * Struct
Struct * Number
Number * Struct
但是我发现如果我允许对第二个参数进行调度,第一个参数的(已经存在的)调度将被覆盖!
有什么方法可以在 S3 中做到这一点吗?
# "generic1" already exists for '*'
'*' <- function(x,y){
UseMethod('*2',y)
}
'*.Struct'<-function(x,y){
# must both be structs, so dispatch 'normally' if not
"times(1)"
}
`*2.Struct`<-function(x,y){
# must both be structs, so dispatch 'normally' if not
"times(2)"
}
给我...
> struct1 * struct2
[1] "times(2)"
> 2 * struct2
[1] "times(2)"
> struct1 * 2
Error in UseMethod("*2", y) :
no applicable method for '*2' applied to an object of class "c('double', 'numeric')"
>
如果我用这个,而不是
'*' <- function(x,y){ UseMethod('*',x)}
然后对第一个参数的调度起作用,相反的情况发生:
> struct1 * 2
[1] "times(1)"
> struct1 * struct2
[1] "times(1)"
> 2* struct1
Error in UseMethod("*", x) :
no applicable method for '*' applied to an object of class "c('double', 'numeric')"
>
看来他们肯定是在互相覆盖。
关于两者如何和平而富有成效地共存有什么想法吗?
你可以检查函数内部:
'*.Struct'<-function(x,y){
if(inherits(x,'Struct') && inherits(y,'Struct'))
"Struct*Struct"
else if(inherits(y,'Struct'))
"N*Struct"
else
"Struct*N"
}
# N.B.: you don't need to redefine `*`,`*2.Struct` etc
例如:
struct1=structure(5,class='Struct')
struct2=structure(3,class='Struct')
struct1*struct2
# [1] "Struct*Struct"
struct1*2
# [1] "Struct*N"
3*struct2
# [1] "N*Struct"
如前所述 here 调度对两个参数都起作用,规则如下:
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’: in that case or if no method is found for either argument the internal method is used.
因此,例如,由于还有一个 *.difftime
方法定义,这些情况将给出带有警告的奇怪结果:
difftimeObj <- Sys.time()-Sys.time()
struct1*difftimeObj
# [1] 0
# attr(,"units")
# [1] "secs"
# attr(,"class")
# [1] "Struct"
# Warning message:
# Incompatible methods ("*.Struct", "*.difftime") for "*"
difftimeObj*struct2
# Time difference of 0 secs
# Warning message:
# Incompatible methods ("*.difftime", "*.Struct") for "*"
而这些反而有效:
struct1*unclass(difftimeObj)
# [1] "Struct*N"
unclass(difftimeObj)*struct2
# [1] "N*Struct"
# skipping dispatching
`*.Struct`(struct1, difftimeObj)
# [1] "Struct*N"
`*.Struct`(difftimeObj, struct2)
# [1] "N*Struct"