5

当我修改复制的 Geom 对象的一部分时,这也会修改底层的原始 Geom。为什么?

(非常感谢用户 Stefan 通过评论我现在删除的上一个问题来确定这个问题)。

library(ggplot2)
GeomFunction$required_aes
#> [1] "x" "y"
GeomFunction2 <- GeomFunction
GeomFunction2$required_aes <- c("x", "y", "fun")
GeomFunction$required_aes
#> [1] "x"   "y"   "fun"

reprex 包(v2.0.1)创建于 2022-01-09

4

1 回答 1

6

因为 ggproto 类对象是环境而不是类似列表的结构,可以使用is.environment(GeomFunction). 环境不遵循例如向量所遵循的修改时复制启发式。

为修改目的制作副本的正确方法是使用ggproto构造函数。从技术上讲,您正在制作GeomFunction.

library(ggplot2)

GeomFunction2 <- ggproto(NULL, GeomFunction)
GeomFunction2$required_aes <- c("x", "y", "fun")

identical(GeomFunction$required_aes, GeomFunction2$required_aes)
#> [1] FALSE

reprex 包(v2.0.1)创建于 2022-01-09

另外,由于 ggproto 对象是环境,我们可以使用它ls()来查看它们包含的内容。

ls(GeomFunction2)
#> [1] "required_aes" "super"
ls(GeomFunction)
#> [1] "draw_panel" "super"
ls(Geom)
#>  [1] "aesthetics"      "default_aes"     "draw_group"      "draw_key"       
#>  [5] "draw_layer"      "draw_panel"      "extra_params"    "handle_na"      
#>  [9] "non_missing_aes" "optional_aes"    "parameters"      "required_aes"   
#> [13] "setup_data"      "setup_params"    "use_defaults"

可以看到层次结构中的每一层都只包含相对于父级的变化,以及一个神秘的super对象,它是一个函数。调用该super函数时,您可以看到它检索父类。

class(GeomFunction2$super())
#> [1] "GeomFunction" "GeomPath"     "Geom"         "ggproto"      "gg"

reprex 包(v2.0.1)创建于 2022-01-09

没有super对象Geom表明这Geom是根类。

该类存在的原因ggproto是允许扩展重用大量代码,而不必从头开始构建它们。理论上,ggproto 类似于 R6 或引用类的面向对象编程,但我认为 R6/引用类有一些缺点,不允许跨包继承它们的类。

于 2022-01-09T00:20:52.833 回答