作用域

函数会开辟一个局部作用域,其中定义的标识符仅能在函数之中使用,也称为标识符在函数中的可见范围。 这种对标识符约束的可见范围,称为作用域。

对外不可见、向内穿透、就近原则。

1、语句块作用域

if、for、switch等语句中定义的变量,可以认为就是该语句块的变量,作用域仅在该语句块中。if、swith、select语句中的每个子句都被视为一个隐式的代码块。

    s0 := []int{1, 2, 3, 4, 5}
    if s0[1] >10 {
        var a int =10
        fmt.Println(10)
    }else if s0[1] < 10 {
        fmt.Println(a) // 此处对变量a不可见
    }

2、显式的块作用域

在任何一个大括号中定义的标识符,其作用域只能在这对大括号中。

    {
        var a string = "你好gopher"
        const b = 123
        c := 'a'
    fmt.Println(a,b,c)
    }
    fmt.Println(a,b,c) // 此处对abc变量不可见

3、universe块

宇宙块,意思就是全局块,不过是语言内建的。预定义的标识符就在这个全局环境中,因此bool、int、 nil、true、false、iota、append等标识符全局可见,随处可用。

4、包块

每一个package包含该包所有源文件,形成的作用域。有时在包中顶层代码定义标识符,也称为全局标 识符。 所有包内定义全局标识符,包内可见。包的顶层代码中标识符首字母大写则导出,从而包外可见,使用 时也要加上包名。例如 fmt.Prinf() 。

// 下面是源码
func Println(a ...any) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}

5、函数块

函数声明的时候使用了花括号,所以整个函数体就是一个显式代码块。这个函数就是一个块作用域。

const a = 123

var b string = "你好gopher"
var c = 768

func show() int {
    return c
}

func main() {
    fmt.Printf("%T %[1]v\n", a) // 这里的a是全局常量a,常量不可取地址
    a := "gopher"
    fmt.Printf("%T %[1]v %p\n", a, &a) // 这里的a是上面刚定义的局部变量a

    fmt.Printf("%T %[1]v %p\n", c, &c)
    c = 1024
    fmt.Printf("%T %[1]v %p\n", c, &c)
    var c = 'c'
    fmt.Printf("%T %[1]v %p\n", c, &c)
    fmt.Println(show()) // 这里show函数return的c是被修改成1024的全局变量的c
}

 标识符作用域

标识符对外不可见,在标识符定义所在作用域外是看不到标识符的

使用标识符,自己这一层定义的标识符优先,如果没有,就向外层找同名标识符——自己优先,由近及远

标识符对内可见,在内部的局部作用域中,可以使用外部定义的标识符——向内穿透

包级标识符,在所在包内,都可见;跨包访问,包级标识符必须大写开头,才能导出到包外,可以在包外使用 xx包名.VarName 方 式访问。例如 fmt.Print()

匿名函数

顾名思义,就是没有名字的函数。在函数定义中,把名字去掉就可以了。

func main() {
    func(x, y int) int {
        res := x + y
        fmt.Println(res)
        return res
    }(10, 11) // 定义并调用

    // 使用变量指向一个匿名函数,通过变量来调用以实现n次调用
    var add = func(x, y int) int {
        return x + y
    }
    fmt.Println(add(1, 2))
}

匿名函数主要作用是用作高阶函数中,它是传入的逻辑。若一个函数允许传入的参数是函数类型,就是 把操作逻辑外置。

高阶函数:形参定义为函数类型或返回值为函数类型,称为高阶函数

// cal并没有实现x,y的操作,而是交给了fu,而fu究竟做什么操
// 作由未来的使用者决定
func cal(x, y int, fu func(int, int) int) int {
    return fu(x, y)
}

func main() {
    add_re := cal(3, 5, func(a, b int) int {
        return a + b
    })
    mul_re := cal(10, 22, func(c, d int) int {
        return c * d
    })
    fmt.Println(add_re, mul_re)
}

函数嵌套

 outer中定义了另外一个函数inner,并且调用了inner。outer是包级变量,main可见,可以调 用。而inner是outer中的局部变量,outer中可见。

 

posted on 2023-06-25 15:10  自然洒脱  阅读(62)  评论(0编辑  收藏  举报