当前位置: 首页 > 面试题库 >

去闭包变量范围

狄宜然
2023-03-14
问题内容

我正在阅读“ CreateSpace Go 2012编程入门”

在第86页上,我发现了这种邪恶的魔力

func makeEvenGenerator() func() uint {
    i := uint(0)

    return func() (ret uint) {
        ret = i
        i += 2
        return
    }
}

// here's how it's called
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())

1)为什么i不复位?2)正在nextEven()返回,uint或者是否Println如此聪明以至于它可以与所有东西配合使用?


问题答案:

为了清楚起见,我将为这两个函数分配名称:

func makeEvenGenerator() func() uint { // call this "the factory"
    i := uint(0)

    return func() (ret uint) { // call this "the closure"
        ret = i
        i += 2
        return
    }
}

工厂返回闭包–函数是Go中的一等公民,即它们可以是右手表达式,例如:

f := func() { fmt.Println("f was called"); }

f() // prints "f was called"

在您的代码中,闭包环绕工厂的上下文,这称为 词法作用域 。这就是变量i在闭包内部可用的原因,而不是作为副本而是作为对i自身的引用。

封闭使用 命名返回值ret。这意味着在闭包内部您将隐式声明ret,在时returnret将返回任何值。

这行:

ret = i

会将的当前值分配iref。它不会改变i。但是,这一行:

i += 2

i在下次调用闭包时更改的值。

在这里,您会找到我为您写的一个封闭示例。我认为它不是非常有用,但可以很好地说明闭包的范围,目的和用法:

package main

import "fmt"

func makeIterator(s []string) func() func() string {
    i := 0
    return func() func() string {
        if i == len(s) {
            return nil
        }
        j := i
        i++
        return func() string {
            return s[j]
        }
    }
}

func main() {

    i := makeIterator([]string{"hello", "world", "this", "is", "dog"})

    for c := i(); c != nil; c = i() {
        fmt.Println(c())
    }

}


 类似资料:
  • JavaScript 是一种非常面向函数的语言。它给了我们很大的自由度。在 JavaScript 中,我们可以随时创建函数,可以将函数作为参数传递给另一个函数,并在完全不同的代码位置进行调用。 我们已经知道函数可以访问其外部的变量。 但是,如果在函数被创建之后,外部变量发生了变化会怎样?函数会获得新值还是旧值? 如果将函数作为参数传递并在代码中的另一个位置调用它,该函数将访问的是新位置的外部变量吗

  • 本章介绍当模板在访问变量时发生了什么事情,还有变量是如何存储的。 当调用 Template.process 方法时,它会在方法内部创建一个 Environment 对象,在 process 返回之前一直使用。 该对象存储模板执行时的运行状态信息。除了这些,它还存储由模板中指令,如 assign, macro, local 或 global 创建的变量。 它不会尝试修改传递给 process 的数据

  • 问题内容: 我知道变量作用域由块的开始和块的结尾包围。如果在块内声明了相同的变量,则会发生编译错误。但是,请看以下示例。 在这里,可以在方法中重新声明,尽管它已经在类中声明了。但是在块中,无法重新声明。 为什么类范围变量的重新声明不产生错误,而方法范围变量的重新声明却产生错误? 问题答案: 这是因为不是变量,而是实例字段。允许局部变量与字段具有相同的名称。为了区分变量和具有相同名称的字段,我们在实

  • 问题内容: 我知道变量作用域由块的开始和块的结尾包围。如果在块内声明了相同的变量,则会发生编译错误。但是,请看以下示例。 在这里,可以在方法中重新声明,尽管它已经在类中声明了。但是在块中,无法重新声明。 为什么类范围变量的重新声明不产生错误,而方法范围变量的重新声明却产生错误? 问题答案: 这是因为不是变量,而是实例字段。允许局部变量与字段具有相同的名称。为了区分变量和具有相同名称的字段,我们在实

  • 问题内容: 这是来自GOPL的示例-“表达式x [i]和x +’A’-‘a’分别引用外部块中x的声明;我们稍后将对此进行解释。” 解释永远不会到来。为什么x [i]引用外部范围中的x?只要在内部块中重新声明x,它就应该在外部块中遮盖x。为什么这样做? http://play.golang.org/p/NQxfkTeGzA 问题答案: 运算符创建一个新变量,并为其分配右侧值。 在for循环的第一个迭

  • 闭包是 JavaScript 一个强大的特性:当函数离开了创建它的位置,仍然可以获取到该位置上存在的所有变量。 本文主要解释闭包的工作方式以及我们为什么要对于变量的无意识共享多加小心。 1、闭包 我们从一个闭包的例子开始吧: function incrementorFactory(start, step) { return function () { // (*) sta