1

1. 立即执行函数

立即执行函数 (immediately invoked function expression, IIFE) 即通过一对括号包裹一个函数体并在紧随其后的一对括号调用此函数:

(function () {
    # code goes here...
})();

立即执行函数最常见的应用场景是,将局部变量的作用域限制在该函数内,以避免冲突。

例如, https://github.com/Microsoft/... 里面也有一个 IIFE.

2. 闭包与私有变量

这个在官方文档 R-intro 和 R-lang 里面都有。

doSomething <- function() {
    n <- 0;
    return(function() {
        n <<- n + 1;
        print(n);
    });
};

thing <- doSomething();

thing() # [1] 1
thing() # [1] 2
thing() # [1] 3
# ...

该代码中,函数 doSomething() 只被执行一次,并把内部的 n 设为 0, 返回值则为一个函数,并被我们赋值给变量 thing. 此后我们每次调用 thing() 的时候,由于 n 仍然在它所有访问的闭包中,我们可以看到该值一直在被增加。

3. 变量具有函数作用域*,但是不被提升

同样这个在官方文档有讲。

(function() { if (TRUE) { y <- 1 }; print(y) })()
# [1] 1

(function() { if (FALSE) { y <- 1 }; print(y) })()
# Error in print(y) : object 'y' not found

还有,运算符 <<- 只对非局部变量赋值,如果找不到任何符合该标识符的非局部变量的话,他会在全局创建一个具有该名称的全局变量:

(function() { test <- 1; test <<- 233; print(test); })();
# [1] 1

test
#[1] 233

以下示例可以证明 R 不对 <- 变量声明做 hoisting:

(function() { (function() { a <<- 1 })(); a <- 2; })();
a # [1] 1

4. do.call() 函数

该函数在官方文档 R-lang 有提及。此外,也可以直接查看该函数相关文档。

有的时候你会想把列表对象展开成函数的参数,但你不晓得应该怎么办。这个时候你需要 do.call():

do.call(what, args, quote = FALSE, envir = parent.frame())

例如:

do.call(function(x, y, z) { return(x + y + z) }, as.list(c(1, 2, 3)));
# [1] 6

5. 函数柯里化

看到这里,你也许会想手动实现一个通用的柯里化函数了。尽管默认并不自带此函数,有很多库帮我们实现这个功能: https://cran.r-project.org/we...

然而自己实现一个其实也不是很难。

https://stackoverflow.com/que... 题目部分的内容非常优雅。

参考该 JavaScript 实现,下面给出我自己的回答。(来自前一篇文章)

Curry <- function(f, len, ...) {
    origList <- list(...);
    ret <- function(...) {
        cur <- c(list(...));
        if (length(cur) < len) {
            return(function(...) {
                return(do.call(ret, c(cur, list(...))));
            });
        }
        return(do.call(f, cur));
    };
    return(do.call(ret, origList));
};

测试:

Curry(function(x, y, z) { return(x + y + z); }, 3, 2)(c(1, 2, 3))(1);
# [1] 4 5 6

* 实际上还有 attach 作用域,并且随着 detach() 终止该作用域,而且若不调用 detach(), 甚至函数结束后被 attach() 的变量名称还在作用域中。

attach() 后声明或赋值同名变量,行为是创建一个遮蔽被 attach 变量的变量。当然,若已存在具有该名称的变量,则该变量会在他的作用域内,遮蔽被 attach 的变量。以上纯属个人总结,不保证正确性。。。

(function() { attach(list(some = 2333)); some <- 1; return(some); })();
# [1] 1

some
# [1] 2333

detach()

some
# Error: object 'some' not found

_CRY
1.2k 声望24 粉丝

How dare we sit quietly


引用和评论

0 条评论