我创建了一个新类来使用 vctrs 打印百分比,如 https://vctrs.r-lib.org/articles/s3-vector.html中所述。当我获取 .R 文件时,它运行良好。但是当我使用 devtools 构建包时,使用 vec_arith 实现的基本操作不再起作用:
pct(0.5, 1L) + pct(0.25, 2L)
#Error: <pct0> + <pct0> is not permitted
但是,类似的情况运行良好:转换很好;vec_math 也可以,可以做sum(pct(0.5, 1L) + pct(0.25, 2L))
我制作了一个可重现的示例,其中包含使用 devtools 2.3.2 和 vctrs 0.3.6 加载带有 percent 类的小包所需的代码。
- 我们使用 devtools 创建一个名为 percenterror 的新包:
create_package("D:\\Statistiques\\Packages\\percenterror")
在这个包的 RStudio 项目内的控制台上,我们声明依赖关系并创建一个新的 .R 文件:
library(devtools)
use_package("vctrs", min_version = "0.3.6")
use_r("percent_class")
- 让我们在打开的 .R 文件中复制以下代码,并使用 roxygen 标签生成 NAMESPACE :
#' Import vctrs in NAMESPACE
#' @import vctrs
#' @keywords internal
#' @name vctrs
NULL
#' Create a vector of class pct using vctrs
#' @param x A double vector.
#' @param digits The number of digits to print. It can then be changed
#' with \code{\link{set_digits}}.
#'
#' @return A numeric vector of class pct.
#' @export
pct <- function(x = double(), digits = 0L) {
x <- vctrs::vec_cast(x, double()) #take anything coercible as a double
digits <- vctrs::vec_recycle(vctrs::vec_cast(digits, integer()), 1L)
new_pct(x, digits)
}
#' @describeIn pct A constructor for class pct.
#' @export
new_pct <- function(x = double(), digits = 0L) {
vctrs::vec_assert(x, double()) #check type or size
vctrs::vec_assert(digits, ptype = integer(), size = 1)
vctrs::new_vctr(x, digits = digits, class = "pct", inherit_base_type = TRUE) #"vctrs_pct"
}
#' Get and set number of digits of vectors with class pct
#' @param x A vector of class \code{\link{pct}} or \code{\link{decimal}}
#' @return \code{\link{get_digits}} : an integer vector with the number of digits.
#' @export
get_digits <- function(x) as.integer(attr(x, "digits"))
#' @rdname get_digits
#' @param value The number of digits to print, as an integer.
#' @return \code{\link{set_digits}} : a vector with the right number of digits.
set_digits <- function(x, value) `attr<-`(x, "digits", as.integer(value))
#' A vec_arith method to allow basic operations for pct
#' @param op Arithmetic operation to do.
#' @param x Pct object.
#' @param y Second object.
#'
#' @export
vec_arith.pct <- function(op, x, y, ...) {
UseMethod("vec_arith.pct", y)
}
#' @export
vec_arith.pct.default <- function(op, x, y, ...) {
vctrs::stop_incompatible_op(op, x, y)
}
#' @export
vec_arith.pct.pct <- function(op, x, y, ...) {
new_pct(vctrs::vec_arith_base(op, x, y),
digits = max(get_digits(x), get_digits(y)))
}
#' @export
vec_arith.pct.numeric <- function(op, x, y, ...) {
new_pct(vctrs::vec_arith_base(op, x, y),
digits = max(get_digits(x), get_digits(y)))
}
#' @export
vec_arith.numeric.pct <- function(op, x, y, ...) {
new_pct(vctrs::vec_arith_base(op, x, y),
digits = max(get_digits(x), get_digits(y)))
}
如果我们这样做library(vctrs)
并获取此文档,
则pct(0.5) + pct(0.25)
可以正常工作。
- 但是,回到控制台,我们创建文档并加载包:
document()
load_all()
在这里,添加不再起作用:
pct(0.5, 1L) + pct(0.25, 2L)
#Error: <pct0> + <pct0> is not permitted
但是找到了方法:
sloop::s3_get_method("vec_arith.pct.pct")
# function(op, x, y, ...) {
# new_pct(vctrs::vec_arith_base(op, x, y),
# digits = max(get_digits(x), get_digits(y)))
# }
#<environment: namespace:percenterror>
该方法似乎与正确的泛型相关联:
sloop::s3_methods_generic("vec_arith.pct")
# # A tibble: 3 x 4
# generic class visible source
# <chr> <chr> <lgl> <chr>
# 1 vec_arith.pct default TRUE percenterror
# 2 vec_arith.pct numeric TRUE percenterror
# 3 vec_arith.pct pct TRUE percenterror
vec_arith.numeric 方法适用于 pct :
1 + pct(0.5)
# <pct0[1]>
# [1] 150%
但事实并非如此,vec_arith_pct
方法不适用于 numeric :
pct(0.5) + 1
#Error: <pct0> + <double> is not permitted
当我们使用 rlang::last_trace() 运行错误跟踪时,我们发现该
pct + pct
操作实际上并没有转到正确的方法,甚至不关心上面定义的函数,因为vec_arith.default
用于代替vec_arith.pct
:
# <error/vctrs_error_incompatible_op>
# <pct0> + <pct0> is not permitted
# Backtrace:
# x
# 1. \-vctrs:::`+.vctrs_vctr`(pct(0.5, 0L), pct(0.25000001))
# 2. +-vctrs::vec_arith("+", e1, e2)
# 3. \-vctrs:::vec_arith.default("+", e1, e2)
# 4. \-vctrs::stop_incompatible_op(op, x, y)
# 5. \-vctrs:::stop_incompatible(...)
# 6. \-vctrs:::stop_vctrs(...)
出了什么问题,该怎么做才能使它起作用?我已经尝试在没有 vctrs:: 调用的情况下使用 ou,导入或不导入 NAMESPACE 中的几乎所有内容,但无法找到发生了什么。
谢谢