微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 vctrs 构建的类放入包时错误的双重调度方法

如何解决将 vctrs 构建的类放入包时错误的双重调度方法

我创建了一个新类来用 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,2L))

我制作了一个可重现的示例,其中包含加载所需的代码 使用 devtools 2.3.2 和 vctrs 0.3.6 的带有百分比类的小包。

  1. 我们使用 devtools 创建了一个名为 percenterror 的新包:
create_package("D:\\Statistiques\\Packages\\percenterror")

在这个包的 RStudio 项目里面的控制台上, 我们声明依赖项并创建一个新的 .R 文件

library(devtools)
use_package("vctrs",min_version = "0.3.6")
use_r("percent_class")
  1. 让我们在打开的 .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,...) {
  vctrs::stop_incompatible_op(op,y)
}


#' @export
vec_arith.pct.pct <- function(op,...) {
  new_pct(vctrs::vec_arith_base(op,y),digits = max(get_digits(x),get_digits(y)))
}

#' @export
vec_arith.pct.numeric <- function(op,get_digits(y)))
}

#' @export
vec_arith.numeric.pct <- function(op,get_digits(y)))
}

如果我们执行 library(vctrs)获取此文档, pct(0.5) + pct(0.25) 工作正常。

  1. 然后,回到控制台,我们创建文档并加载包:
document()
load_all()

在这里添加不再起作用:

pct(0.5,2L)
#Error: <pct0> + <pct0> is not permitted

但是找到了方法

sloop::s3_get_method("vec_arith.pct.pct")
# function(op,...) {
#   new_pct(vctrs::vec_arith_base(op,#           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 方法不适用于数字:

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("+",e2)
# 4.     \-vctrs::stop_incompatible_op(op,y)
# 5.       \-vctrs:::stop_incompatible(...)
# 6.         \-vctrs:::stop_vctrs(...)

出了什么问题,怎么做才能使它正常工作?我试过你没有 vctrs:: 调用、导入或不导入 NAMESPACE 中的几乎所有内容, 但无法设法找到发生了什么。

谢谢

解决方法

您需要添加 roxygen2 @method 标签以将您的 vec_arith. 函数导出为方法:

#' A vec_arith method to allow basic operations for pct
#' @param op Arithmetic operation to do.
#' @param x Pct object.
#' @param y Second object.
#'
#' @method vec_arith pct
#' @export
vec_arith.pct <- function(op,x,y,...) {
  UseMethod("vec_arith.pct",y)
}

#' @method vec_arith.pct default
#' @export
vec_arith.pct.default <- function(op,...) {
  vctrs::stop_incompatible_op(op,y)
}

#' @method vec_arith.pct pct
#' @export
vec_arith.pct.pct <- function(op,...) {
  new_pct(vctrs::vec_arith_base(op,y),digits = max(get_digits(x),get_digits(y)))
}

#' @method vec_arith.pct numeric
#' @export
vec_arith.pct.numeric <- function(op,get_digits(y)))
}

#' @method vec_arith.numeric pct
#' @export
vec_arith.numeric.pct <- function(op,get_digits(y)))
}

对于大多数泛型,此要求已从 vctrs 的双重调度机制中删除,但目前 vec_arith() 仍然需要:https://github.com/r-lib/vctrs/issues/1287

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。