From 31e18b593fc05a878dd6cf0390104f18cf941222 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 2 Oct 2014 19:46:55 -0400 Subject: [PATCH] 6.8 --- README.md | 2 +- eBook/06.7.md | 2 +- eBook/06.8.md | 99 +++++++++++++++++++++++++++++++++++++++++++++- eBook/06.9.md | 3 ++ eBook/directory.md | 1 + 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 eBook/06.9.md diff --git a/README.md b/README.md index b4d317e..3d65666 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 翻译进度 -6.7 [将函数作为参数](eBook/06.7.md) +6.8 [闭包](eBook/06.8.md) ## 支持本书 diff --git a/eBook/06.7.md b/eBook/06.7.md index f86082f..0df1b82 100644 --- a/eBook/06.7.md +++ b/eBook/06.7.md @@ -55,5 +55,5 @@ func run(op binOp, req *Request) { … } ## 链接 - [目录](directory.md) -- 上一节:[递归函数](06.6.md) +- 上一节:[将函数作为参数](06.7.md) - 下一节:[闭包](06.8.md) \ No newline at end of file diff --git a/eBook/06.8.md b/eBook/06.8.md index eee6d89..c764324 100644 --- a/eBook/06.8.md +++ b/eBook/06.8.md @@ -1,3 +1,100 @@ # 6.8 闭包 -147 \ No newline at end of file +当我们不希望给函数起名字的时候,可以使用匿名函数,例如:`func(x, y int) int { return x + y }`。 + +这样的一个函数不能够独立存在(编译器会返回错误:`non-declaration statement +outside function body`),但可以被赋值于某个变量,即保存函数的地址到变量中:`fplus := func(x, y int) int { return x + y }`,然后通过变量名对函数进行调用:`fplus(3,4)`。 + +当然,您也可以直接对匿名函数进行调用:`func(x, y int) int { return x + y } (3, 4)`。 + +下面是一个计算从 1 到 1 百万整数的总和的匿名函数: + +```go +func() { + sum = 0.0 + for i := 1; i <= 1e6; i++ { + sum += i + } +}() +``` + +表示参数列表的第一对括号必须紧挨着关键字 `func`,因为匿名函数没有名称。花括号 `{}` 涵盖着函数体,最后的一对括号表示对该匿名函数的调用。 + +下面的例子展示了如何将匿名函数赋值给变量并对其进行调用(function_literal.go): + +```go +package main + +import "fmt" + +func main() { + f() +} +func f() { + for i := 0; i < 4; i++ { + g := func(i int) { fmt.Printf("%d ", i) } + g(i) + fmt.Printf(" - g is of type %T and has value %v\n", g, g) + } +} +``` + +输出: + +``` +0 - g is of type func(int) and has value 0x681a80 +1 - g is of type func(int) and has value 0x681b00 +2 - g is of type func(int) and has value 0x681ac0 +3 - g is of type func(int) and has value 0x681400 +``` + +我们可以看到变量 `g` 代表的是 `func(int)`,变量的值是一个内存地址。 + +所以我们实际上拥有的是一个函数值:匿名函数可以被赋值给变量并作为值使用。 + +**练习 6.8** 在 main 函数中写一个用于打印 `Hello World` 字符串的匿名函数并赋值给变量 `fv`,然后调用该函数并打印变量 `fv` 的类型。 + +匿名函数像所有其它可以接受或不接受参数。下面的例子展示了如何传递参数到匿名函数中: + +```go +func (u string) { + fmt.Println(u) + … +}(v) +``` + +请学习以下示例并思考(return_defer.go):函数 `f` 返回时,变量 `ret` 的值是什么? + +```go +package main + +import "fmt" + +func f() (ret int) { + defer func() { + ret++ + }() + return 1 +} +func main() { + fmt.Println(f()) +} +``` + +变量 `ret` 的值为 2,因此 `ret++`,这是在执行 `reutrn 1` 语句后发生的。 + +这可用于在返回语句之后修改返回的 `error` 时使用。 + +**defer 语句和匿名函数** + +关键字 `defer` (详见第 6.4 节)经常配合匿名函数使用,它可以用于改变函数的命名返回值。 + +匿名函数还可以配合 `go` 关键字来作为 goroutine 使用(详见第 14 章和第 16.9 节)。 + +匿名函数同样被称之为闭包(函数式语言的术语):它们被允许调用定义在其它环境下的变量。闭包可使得某个函数捕捉到一些外部状态,例如:函数被创建时的状态。另一种表示方式为:一个闭包继承了函数所声明时的作用域。这种状态(作用域内的变量)都被共享到闭包的环境中,因此这些变量可以在闭包中被操作,直到被销毁,详见第 6.9 节中的示例。闭包经常被用作包装函数:它们会预先定义好 1 个或多个参数以用于包装,详见下一节中的示例。另一个不错的应用就是使用闭包来完成更加简洁的错误检查(详见第 16.10.2 节)。 + +## 链接 + +- [目录](directory.md) +- 上一节:[递归函数](06.6.md) +- 下一节:[应用闭包:将函数作为返回值](06.9.md) \ No newline at end of file diff --git a/eBook/06.9.md b/eBook/06.9.md new file mode 100644 index 0000000..13ff84b --- /dev/null +++ b/eBook/06.9.md @@ -0,0 +1,3 @@ +# 6.9 应用闭包:将函数作为返回值 + +150 \ No newline at end of file diff --git a/eBook/directory.md b/eBook/directory.md index 0442ca2..8a2216d 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -54,6 +54,7 @@ - 6.6 [递归函数](06.6.md) - 6.7 [将函数作为参数](06.7.md) - 6.8 [闭包](06.8.md) + - 6.9 [应用闭包:将函数作为返回值](06.9.md) - 第7章:数组(array)与切片(slice) - 第8章:Maps - 第9章:包(package)