如何让R6类用户提供可访问self的自定义calc函数?
解决方案
调整自定义calc函数的环境方向是正确的,这能让用户的代码自然访问R6实例的self对象。要避免依赖内部属性.__enclos_env__,可以通过environment(self)获取实例的封闭环境,这是更规范的公开访问方式。
优化后的R6类实现
library(R6) B <- R6Class("B", public = list( initialize = function(calc) { # 获取实例的封闭环境,替代内部的.__enclos_env__ inst_env <- environment(self) private$calc <- calc # 将自定义calc的环境设置为实例的封闭环境 environment(private$calc) <- inst_env }, run = function(x) { private$calc(x) }, result_codes = list(OK = 1, NOK = 2) ), private = list( calc = NULL ) )
测试代码
# 用户自定义calc函数,直接使用self b <- B$new(function(x) { if (x >= 0) { self$result_codes$OK } else { self$result_codes$NOK } }) b$run(1) # 返回1 b$run(-1) # 返回2
原理说明
environment(self)会返回R6实例的封闭环境,这个环境包含了self和private对象的作用域,是公开且稳定的访问方式,不会依赖内部未文档化的属性。- 将自定义
calc函数的环境设置为实例的封闭环境后,函数内部就能直接识别self,和类中定义的方法拥有一致的作用域。
备选方案(显式传递self)
如果不想调整函数环境,也可以在调用calc时显式传递self作为参数,但需要用户修改自定义函数的参数列表:
B <- R6Class("B", public = list( initialize = function(calc) { private$calc <- calc }, run = function(x) { # 调用时传递self private$calc(self, x) }, result_codes = list(OK = 1, NOK = 2) ), private = list( calc = NULL ) ) # 用户需要接收self参数 b <- B$new(function(self, x) { if (x >= 0) { self$result_codes$OK } else { self$result_codes$NOK } }) b$run(-1) # 返回2
这种方式无需修改环境,但用户需要额外处理self参数,不如调整环境的方式直观。
内容的提问来源于stack exchange,提问作者thothal
相关产品推荐
相关产品推荐

