R函数未传必填参数subsample_size仍无报错运行原因咨询
我正在协助同事为其开发的R包添加功能,用for循环实现了非参数bootstrapping(非参数自助法),核心重采样代码如下:
# perform resampling # resample `subsample_size` values with or without replacement replicate_size times for (i in 1:replicate_size) { if (replacement == TRUE) { # bootstrapping z <- sample(x, size = subsample_size, replace = TRUE) zz <- sample(x, size = subsample_size, replace = TRUE) } else { # subsampling z <- sample(x, size = subsample_size, replace = FALSE) zz <- sample(x, size = subsample_size, replace = FALSE) } # calculate statistic boot_samples[i] <- min(zz) - max(z) }
这段循环嵌套在另一层for循环中,外层循环本身又在函数内部。现有代码存在效率更高的实现方式,但由于同事仅掌握基础编码结构,只能保留原有写法。
运行函数时传入了必填参数replicate_size、replacement,唯独漏传了重采样必需的subsample_size参数,但代码没有抛出subsample_size缺失的错误,反而正常运行。
补充说明:把上述for循环单独拿到函数外部运行时,会按预期抛出参数缺失的错误。
这个现象是R的词法作用域规则与参数惰性求值特性共同导致的:
你漏传的函数形参subsample_size,在代码运行时全程没有被实际访问到,自然不会触发缺失报错。
最常见的触发场景是:包裹这段代码的外层for循环,恰好把循环变量命名为subsample_size(比如同事写了类似for (subsample_size in c(50, 100, 200))的逻辑,遍历不同的抽样子样本量)。R查找变量时遵循就近原则,会从当前执行环境往外层逐层搜索符号,执行内层sample调用时,首先会找到外层循环环境中定义的subsample_size循环变量,直接用这个值完成抽样,根本不会去触碰函数形参中那个漏传的subsample_size。
R的函数参数采用惰性求值机制,参数只有在代码中被实际访问、求值时,才会检查是否缺失、是否合法。由于漏传的形参被外层同名变量全程遮蔽,从头到尾没有被调用过,完全不会触发参数缺失的报错。
而把内层循环单独拿到全局环境运行时,全局环境和默认搜索路径上都不存在subsample_size对象,因此会正常抛出找不到对象的错误。
其他可能的同类触发逻辑还包括:
- 函数内部、进入循环前的代码里写了隐式容错,比如
if (missing(subsample_size)) subsample_size <- length(x),漏传时自动用全量样本量作为抽样大小,只是这段逻辑没有加注释,没有被注意到 - 函数定义所在的闭包环境、或者包的命名空间中提前定义了
subsample_size对象,运行时被R搜索到并调用
内容的提问来源于stack exchange,提问作者compbiostats

