在R中允许使用用户定义的运算符,但似乎只接受% %
个类似的运算符。是否可以绕过此限制来定义运算符,例如>>
或某些不像% %
的运算符?
运算符必须是真正的运算符,以便我们可以像1 >> 2
一样使用它,而不必像">>"(1,2)
那样使用它。
答案 0 :(得分:17)
没有。 R只允许你
`+`
或实际上`<-`
)和%…%
这些是我们必须遵守的规则。但是,在这些规则中,一切都是公平的。例如,我们可以为字符串重新定义`+`
以执行连接,而不会破坏其正常含义(添加):
`+`
# function (e1, e2) .Primitive("+")
这是旧的定义,我们希望为数字保留:
`+.default` = .Primitive('+')
`+.character` = paste0`1
`+` = function (e1, e2) UseMethod('+')
1 + 2
# [1] 3
'hello' + 'world'
# [1] "helloworld"
这利用了R中的S3类系统,使`+`
在其第一个参数的类型上完全通用。
可以重新定义的运算符列表非常折衷。首先,它包含以下运算符:
+
,-
,*
,/
,^
,&
,|
,:
,::
,:::
,$
,=
,<-
,<<-
,==
,<
,{ {1}},<=
,>
,>=
,!=
,~
,&&
,||
,{{1 }},!
,?
,@
,:=
,(
,{
在此列表中,一个特定的运算符值得注意:[
是一个可覆盖的运算符(例如{data.table}使用它)但与此列表中的大多数其他运算符不同,它没有默认实现。< / p>
同样,您可以定义几乎所有运算符的赋值版本,而不仅仅是具有预定义赋值的赋值版本(例如[[
)。例如,`:=`
和`[<-`
也缺少默认实现。这就是以下代码失败的原因:
`(<-`
但是可以通过定义运算符来使代码工作:
`{<-`
每个函数都有相同的功能,包括几乎所有的运算符 1 ,甚至是控制结构(参见本答案下面的注释)。
相比之下,a = 1
(a) = 2
# Error in (a) = 2 : could not find function "(<-"
{a} = 3
# Error in { : could not find function "{<-"
不是真正的运算符:它是`(<-` = `{<-` = function (x, value) value
的语法别名。用户可以定义自己的`**`
函数,但不能通过代码`^`
调用它,因此它不是可覆盖的运算符(除了通过覆盖`**`
)。
同样,您可以通过重新定义a ** b
来覆盖`^`
(仅限)。这似乎很少有意义 - 但至少有一个很好的例子,定义较少冗长的lambdas:
->
1 唯一的例外是赋值运算符:您不能通过重新定义<-
来更改> sapply(1 : 4, x -> 2 * x)
[1] 2 4 6 8
的含义(对于a <- b <- c
也是如此,{{ 1}}和`<-<-`
),由于语言operator precedence and associativity rules。但是,以下代码调用`=<-`
和`<<-`
,如果未定义其中任何一个,则会失败:
`:=`
搞砸了。
答案 1 :(得分:4)
您可以执行此类操作,但您可能希望将这些对象分配到新环境以确保安全。
> "^" <- function(x, y) `-`(x, y) ## subtract y from x
> 5 ^ 3
# [1] 2
> "?" <- function(x, y) sum(x, y) ## add x and y
> 5 ? 5
# [1] 10