一、函数定义

函数被证实地称为“闭包(closure)”,R中的函数有三个基本属性,前两者是构成函数,后者是这个函数的生存环境。

#实例,y z 是numeric
f <- function(x, y = 1, z = 2) {
    paste(x, y, z)
}
f(0)
## [1] "0 1 2"
formals(f) <- alist(x =, y = "mm", z = "gg")
f("ss")
## [1] "ss mm gg"
#打印函数体
body(f)
## {
##     paste(x, y, z)
## }

二、作用域(Scoping Rules)

在计算机程序设计中,变量是名字(name)与实体(entity)的绑定(binding)。一段程序代码中所用到的名字并不总是有效(或者说:可用的),而限定这个变量名字具有可用性的代码范围就是这个名字的作用域。

w <- 1
func <- function(y){ 
    a <- 2
    h <- function(){
        b <- 1
        z <- b * (w + y) + b
        h_scoping_values <- list("ss" = b, "xx" = y, "kk" = z, ls())
        h_scoping_values
    }
    func_scoping_values <- list("mm" = a, "gg" = h, "jj" = ls())
    func_scoping_values
}
globalenv_values <- ls()
#作用域范围:h < func < globalenv 

此例中,R:函数变量寻值过程:首先在本函数内部,然后到上一层env,可以是f或者env,直至globalenv,最后是load的其他的package。

print(globalenv_values) #全局变量中有func、w
## [1] "f"    "func" "w"
func(3)  #func函数值,有变量a h y
## $mm
## [1] 2
## 
## $gg
## function () 
## {
##     b <- 1
##     z <- b * (w + y) + b
##     h_scoping_values <- list(ss = b, xx = y, kk = z, ls())
##     h_scoping_values
## }
## <environment: 0x000000001af3a350>
## 
## $jj
## [1] "a" "h" "y"
func(3)[["gg"]]() #h()函数中有变量"b"、"z"
## $ss
## [1] 1
## 
## $xx
## [1] 3
## 
## $kk
## [1] 5
## 
## [[4]]
## [1] "b" "z"
y <- 10
func1 <- function(x){
    y <- 2
    y^ 2 + func2(x) + func3(x)
}
func2 <- function(x){
    x*y
}
#func1(3) #Error in func3(x) : could not find function "func3"
y <- 10
func1 <- function(x){
    y <- 2
    y^ 2 + func2(x) + func3(x)
}
func2 <- function(x){
    x*y
} 
# 在调用func3之前,必须有func3的定义
func3 <- function(x){
    x+y
}
func1(3)
## [1] 47

实例1:

a <- function(x){
    e <- new.env()
    e$x <- 1
    c <- b(x)
    return(c(c, e$y, e$z))
}
b <- function(x){
    x <- e$x + x
    e$y <- x + 1
    e$z <<- x + 2
    return(x)
}
e <- new.env()
e$x <- 2
a(3)
## [1] 5

思路分析图: 实例2:

rm(list = ls()) #清除所有变量
a <- function(x){
    e <- new.env()
    e$x <- 1
    b <- function(x){
        x <- e$x + x
        e$y <- x + 1
        e$z <<- x + 2 # 将z变成全局变量
        return(x)
    }
    c <- b(x)
    return(c(c, e$y, e$z))
}
e <- new.env()
e$x <- 2
a(3) 
## [1] 4 5 6

思路分析图:

ls() #打印全局变量
## [1] "a" "e"
a <- function(x){
    e <- new.env()
    e$x <- 1
    b <- function(x){
        x <- e$x + x
        e$y <- x + 1
        e$z <<- x + 2 # 将z变成全局变量
        return(x)
    }
    c <- b(x)
    ls()  #打印a函数的所有变量空间 #"b" "c" "e" "x"
}
e <- new.env()
e$x <- 2
ls(envir = e) #"x"
## [1] "x"
a(2) 
## [1] "b" "c" "e" "x"
a <- function(x){
    e <- new.env()
    e$x <- 1
    b <- function(x){
        x <- e$x + x
        e$y <- x + 1
        e$z <<- x + 8 # 将z变成全局变量
    }
    c <- b(x)
    ls(envir = e) #"x" "y" "z"
}
e<- new.env()
e$x <- 2
a(2)
## [1] "x" "y" "z"
a <- function(x){
    e <- new.env()
    e$x <- 1
    b <- function(x){
        x <- e$x + x
        e$y <- x + 1
        e$z <<- x + 2 # 将z变成全局变量
        ls(envir = e)  #"x" "y" "z"
    }
    c <- b(x)
    c#打印b函数的所有变量空间
}
e <- new.env()
e$x <- 2
a(2)
## [1] "x" "y" "z"

探究全局环境变量赋值符号“<<-”作用域。

情形一:函数a调用函数b中的局部变量

rm(list=ls())
func1<- function(x){
        a <- 3
        a*x + 3
    }
func2 <- function(x){
        a*x
}
b <- func1(2)
#func2(b) #Error in func2(func1(2)) : object 'a' not found

情形二:函数a调用函数b中全局变量,但是函数b没有环境

rm(list=ls())
func1<- function(x){
        a <<- 3
        a*x + 3
    }
func2 <- function(x){
        a*x
}
#func2(func1(2))  #Error in func2(func1(2)) : object 'a' not found

情形三:函数a调用函数b中全局变量,函数b环境在函数a调用过程中创建了环境。

rm(list=ls())
func1<- function(x){
        a <<- 3
        a*x + 3
    }
func2 <- function(x){
        a*x
}
b <- func1(2)
func2(b)
## [1] 27
## 结果为27

情形四:工作空间是不是最顶层环境?

rm(list=ls())
func1<- function(x){
        a <<- 3
        a*x + 3  #9
    }
func2 <- function(x){
        a*x
}
a <- 1
func2(func1(2)) #func1(2) = 9,此时先去工作空间查找到a=1,而不是取全局变量a=3
## [1] 9
## 结果为9

通过分析:全局变量a需要在一个特定的环境中,最后代码块中,a存在func1的环境中,当func2中需要a时,先func2函数中找a再从创建func2函数的环境找,最后在全局变量找,全局变量应该是最顶层。