`NextMethod()` 的内部工作原理

Posted

技术标签:

【中文标题】`NextMethod()` 的内部工作原理【英文标题】:The inner workings of `NextMethod()` 【发布时间】:2014-01-22 19:48:32 【问题描述】:

我试图弄清楚NextMethod() 的工作原理。我在 Chambers & Hastie (edts.) 的 Statistical Models in S (1993, Chapman & Hall) 中找到了关于 S3 类系统的最详细解释,但我发现有关 @987654322 的部分@ 调用有点晦涩。以下是我试图理解的相关段落(第 268-269 页)。

现在转向作为调用结果调用的方法 NextMethod(),它们的行为就像是从 以前的方法有一个特殊的调用。调用中的参数 继承的方法在数量、顺序和实参上都相同 名称与调用当前方法中的名称相同(因此,在 对泛型的调用)。然而,参数的表达式, 是当前的相应形式参数的名称 方法。例如,假设表达式print(ratings) 具有 调用了方法print.ordered()。当此方法调用 NextMethod(),这相当于调用print.factor() print.factor(x) 的形式,其中 x 在这里是框架中的 x print.ordered()。如果多个参数与形式参数匹配 “...”,这些参数在对继承的调用中表示 方法 y 特殊名称“..1”、“..2”等。评估者认可 这些名称并适当地对待它们(参见第 476 页的 示例)。

存在这个相当微妙的定义是为了确保 S 中的函数调用尽可能干净地传递给 方法(比较 Becker、Chambers 和 Wilks 的新 S 语言, 第 354 页)。特别是:

在调用NextMethod() 时,参数会以其当前值从当前方法传递到继承的方法。 延迟评估继续有效;未评估的参数保持未评估。 继承的方法中仍然缺少缺少的参数。 通过...”形式参数传递的参数以正确的参数名称到达。 框架中与调用中的实际参数不对应的对象将不会传递给继承的方法。"

继承过程基本上是透明的 论据去。

我感到困惑的两点是:

    什么是“当前方法”,什么是“以前的方法”? “对继承方法的调用中的参数”、“参数的表达式”和“当前方法的相应形式参数的名称”有什么区别?

一般来说,如果有人能以清晰的方式重述上述段落中的描述,我将不胜感激。

【问题讨论】:

【参考方案1】:

很难看完所有这篇文章,但我认为这个小例子可以帮助揭开NextMethod 调度的神秘面纱。

我创建了一个具有 2 个类属性(继承)“第一”和“第二”的对象。

x <- 1
attr(x,'class') <- c('first','second')

然后我创建一个generic 方法Cat 来打印我的对象

Cate <- function(x,...)UseMethod('Cate')

我为每个类定义了Cate 方法。

Cate.first <- function(x,...)
  print(match.call())
  print(paste('first:',x))
  print('---------------------')
  NextMethod()                ## This will call Cate.second


Cate.second <- function(x,y)
  print(match.call())
  print(paste('second:',x,y))

现在您可以使用此示例检查Cate 呼叫:

 Cate(x,1:3)
Cate.first(x = x, 1:3)
[1] "first: 1"
[1] "---------------------"
Cate.second(x = x, y = 1:3)  
[1] "second: 1 1" "second: 1 2" "second: 1 3"
对于 Cate.second,之前的方法是 Cate.first 参数 x 和 y 从当前方法传递到继承的 方法及其在调用 NextMethod() 时的当前值。 通过“...”形式参数传递的参数 y 以正确的参数名称到达 Cate.second(x = x, y = 1:3)

【讨论】:

【参考方案2】:

考虑这个例子,其中泛型函数f 被调用并调用f.ordered,然后使用NextMethodf.ordered 调用f.factor

f <- function(x) UseMethod("f")  # generic
f.ordered <- function(x)  x <- x[-1]; NextMethod() 
f.factor <- function(x) x # inherited method
x <- ordered(c("a", "b", "c"))

class(x)
## [1] "ordered" "factor" 

f(x)
## [1] b c
## Levels: a < b < c

现在考虑原文:

现在转到由于调用 NextMethod() 而调用的方法, 这些行为就好像它们是从以前的方法中调用的一样 一个特殊的电话。

这里 f 调用 f.ordered 调用 f.factor 所以方法“调用为 调用 NextMethod 的结果是 f.factor ,前一个方法是 f.ordered.

对继承方法的调用中的参数在 数字、顺序和实际参数名称与调用 当前方法(因此,在对泛型的调用中)。这 然而,参数的表达式是 当前方法的相应形式参数。假设,对于 例如,表达式 print(ratings) 调用了该方法 打印.ordered()。当此方法调用 NextMethod() 时,这是 相当于以 print.factor(x) 形式调用 print.factor(), 其中 x 是 print.ordered() 框架中的 x

现在我们切换视角,我们坐在f.ordered 所以现在f.ordered 是当前方法,f.factor 是继承方法。

f.ordered 调用NextMethod() 时,构造了一个特殊调用 调用f.factor,其参数与传递给f.ordered的参数相同,并且 到通用f 除了它们引用 f.ordered 中的参数版本(其中 在这里有所不同,因为f.ordered 在调用之前更改了参数 f.factor

【讨论】:

以上是关于`NextMethod()` 的内部工作原理的主要内容,如果未能解决你的问题,请参考以下文章

部分原像技术

PHP的内部工作原理

简述ic卡芯片内部结构,工作原理及应用。

innerHTML 的内部工作原理

Worker的内部工作原理

简述ic卡芯片内部结构,工作原理及应用。