Go学习八:包的访问权限、变量作用域、闭包包概述自定义包

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

包概述

  • 包(package)是Go语言中组织单元.包是逻辑上的分组.而物理上的分组是不同的文件夹,文件夹和包一般是对应的
  • 把多个文件放入同一个文件夹中,这些文件就是在同一个包中.
  • 虽然允许源码文件的package和文件夹名不同但是最终编译后都会把文件的package编译成文件夹名称.所以为防止错误最好把文件的package和文件夹名称设置成相同的
  • 一个Go语言项目必须要有main包,其他自定义名称的包个数任意,根据自己的需求即可.
  • Go语言在寻找包时会从GOPATH/src 路径中寻找包,如果不存在去GOROOT/src(Go语言标准库源码所在文件夹)下找
  • 不同包下资源可以相互访问,在导入其他包后,可以访问包下首字母大写的内容
  • 同包下不同文件中全局资源可以随意访问

自定义包

  • 新建项目后在项目下新建src文件夹,在src文件夹中新建demo文件
  • 在demo文件中新建demo1.go和demo2.go文件
  • demo1.go文件源码如下
package demo//包为demo

import "fmt"

func demo1(){
	fmt.Println("执行demo1")
}
复制代码
  • demo2.go文件源码如下
package demo//包为demo

import "fmt"

func Demo2()  {//函数名大写才能被其他包访问
	fmt.Println("执行demo2")
	demo1()//同包下内容任意访问
}
复制代码
  • 在项目根目录下新建main.go,源码如下
package main

import "demo"

func main() {
	demo.Demo2()
}
复制代码
  • 运行整个项目后,发现可以正常调用Demo2()函数
  • 整个程序目录结构如下

变量作用域

  • 变量声明位置决定了变量的可访问范围(哪里能调用到变量)
  • Go语言中变量的有效范围如下
    • 函数级别:变量声明在函数内部,只有在函数内部才能访问,称变量为局部变量
    • package 包级别,在当前包下都可以访问.称变量为全局变量.变量声明在函数外面
    • 应用级别,在整个应用下任何包内都可以访问.通过首字母大小写控制

局部变量

  • 局部变量一定是在函数内部
  • 在哪个{}内部声明,只能在哪个{}内部访问
func test1() {
	i := 2 //从此处开始到test1结束}任何位置都能调用i
	if i>=2{
		j:=3
		fmt.Println(i+j)//此处可以访问i
	}
	fmt.Println(i)
	//fmt.Println(j)//此处不能调用j,超出声明j时{}外
}
func test2() {
	fmt.Println(i) //此处无法调用test1()中的i
}
复制代码

全局变量

  • 全局变量声明到函数外部,整个包都可以访问
  • 如果全局变量首字母大写,跨包也可以访问.
  • 声明全局变量时规范是
var (
	变量名
	变量名=值
)
复制代码
  • 全局变量代码示例
var (
	name = "smallming"
	age  = 17
)

func demo1() {
  	fmt.Println("名字:",name)
}

func demo2() {
  	fmt.Println("年龄:",age)
}
复制代码

闭包概述

  • 闭包不是Go语言独有的概念,在很多编程语言中都有闭包
  • 闭包就是解决局部变量不能被外部访问一种解决方案
  • 是把函数当作返回值的一种应用

代码演示

  • 总体思想为:在函数内部定义局部变量,把另一个函数当作返回值,局部变量对于返回值函数就相当于全局变量,所以多次调用返回值函数局部变量的值跟随变化
package main

import "fmt"

func main() {
	//res其实就是test1返回值函数,和之前匿名函数变量一个道理
	res := test1()
	fmt.Println(res()) //输出2
	fmt.Println(res()) //输出3
	fmt.Println(res()) //输出4
}

//注意此处,返回值类型是func int
func test1() func() int {
	i := 1
	return func() int {
		i = i + 1
		return i
	}
}
复制代码
  • 如果重新调用test1()会重新声明及赋值局部变量i
package main

import "fmt"

func main() {
	f := test1()
	fmt.Println("f的地址", f) //输出匿名函数地址
	fmt.Println("f:", f()) //调用匿名函数输出2
	fmt.Println("f:", f()) //调用匿名函数输出3
	k := test1()
	fmt.Println("k的地址", k) //输出匿名函数地址,与f相等
	fmt.Println("k:", k()) //调用匿名函数输出2
	fmt.Println("f:", f()) //输出:4
	fmt.Println("k:", k()) //输出:3
}

func test1() func() int {
	i := 1
	return func() int {
		i++
		// 每调用一次test1()输出的地址不一样
		fmt.Println("i的地址:", &i)
		return i
	}
}

复制代码