系列文章
【golang学习之旅】使用VScode安装配置Go开发环境
【golang学习之旅】报错:a declared but not used
【golang学习之旅】Go 的基本数据类型
【golang学习之旅】深入理解字符串string数据类型
【golang学习之旅】go mod tidy
【golang学习之旅】记录一次 panic case : reflect: reflect.Value.SetInt using unaddressable value
【golang学习之旅】记录一次 error case : full error output: cc1: error: unrecognized command line option
【golang学习之旅】Go程序快速开始 & Go程序开发的基本注意事项
【golang学习之旅】Go语言常用转义字符
【golang学习之旅】Go中的变量(1)
【golang学习之旅】Go中的变量——基本数据类型(1)
【golang学习之旅】Go中的变量——基本数据类型(2)
- 系列文章
- 指针
- 函数
- 基本语法
- 包
- 函数注意事项和细节讨论
- init()函数
- 匿名函数
- 闭包
指针
基本数据类型,变量存的就是值,所以也叫值类型。
指针类型,指针变量存的是一个地址,这个地址所指向的空间存的才是值
package main
import "fmt"
func main() {
var a int = 10
fmt.Println("a 的地址:", &a)
// ptr是一个指针变量,它的类型是*int,它指向int类型的变量a
var ptr *int = &a
fmt.Printf("ptr的值: %v, ptr 的地址: %v\n", ptr, &ptr)
fmt.Println("ptr指向的值:", *ptr)
// 修改ptr指向的值
*ptr = 20
fmt.Println("修改后a的值:", a)
}
输出:
a 的地址: 0xc00000a0b8
ptr的值: 0xc00000a0b8, ptr 的地址: 0xc00005a028
ptr指向的值: 10
修改后a的值: 20
-
获取变量的地址使用
&
符号 -
获取指针类型所指向的值,使用
*
-
可以通过指针修改所指向变量的值
练习:
值类型有:基本数据类型(int系列,float系列,bool,string)、复杂数据类型中的复合数据类型(数组和结构体)
引用类型有:非值类型就是引用类型
函数
基本语法
func 函数名(形参列表) (返回值列表){
执行语句...
}
- 函数声明包含一个函数名,参数列表, 返回值列表和函数体。如果函数没有返回值,则返回列表可以省略
- 函数可以没有参数或接受多个参数
- 函数可以返回任意数量的返回值。有返回值的函数,必须有明确的终止语句,否则会引发编译错误
包
Go中的每一个文件都属于一个包,也就是说Go是以包的形式来管理文件和项目目录结构的。
包的作用:
- 区分相同名字的函数、变量等标识符。不同包的文件中允许重名的标识符
- 当程序文件很多时,可以很好的管理项目。比如module包、dao包、service包等等
- 控制函数、变量等访问范围
包的注意事项:
-
文件的包名通常和文件所在的文件夹名一致,一般为小写字母。
-
当一个文件要使用其他包的函数或变量时,需先引入对应的包
-
引入方式1:
import “包名/包路径”
-
引入方式2:
import ( "包名" "包名" )
-
-
package
指令在文件第一行,然后是import
指令。接下来才是变量、函数声明等等 -
在访问其他包函数、变量时,其语法是
包名.函数名
-
如果包名较长,Go支持给包取别名。取别名后,原来的包名就不能使用了
-
在同一个包下,不能有相同的函数名,否则报重复定义
函数注意事项和细节讨论
-
函数的形参列表可以是多个,返回值也可以是多个
-
函数的命名遵循标识符命名规范,首字母不能是数字。首字母是大写则该函数可以被其他包访问到,如果是小写,只能被本包文件使用
-
基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改值不会影响原值
package main
import (
"fmt"
)
func test(name string) {
name = "test"
fmt.Println("test() ", name)
}
func main() {
name := "main"
test(name)
fmt.Println("main() ", name)
}
输出:
test() test
main() main
-
如果希望函数内的变量能够修改函数外的变量(指的是以值传递的方式的基本数据类型),可以传入变量的地址,函数内以指针的方式操作变量(从效果上类似引用数据类型的使用)
package main import ( "fmt" ) func test(name *string) { *name = "test" fmt.Println("test() ", *name) } func main() { name := "main" test(&name) fmt.Println("main() ", name) } 输出: test() test main() test
-
在Go中,函数本身也是一种数据类型,可以赋值给一个变量,通过该变量可以实现对函数的调用
package main import ( "fmt" ) func getSum(n1, n2 int) int { return n1 + n2 } func main() { a := getSum fmt.Printf("a 的类型 %T\n", a) res := a(1, 2) // 等价于 res := getSum(1, 2) fmt.Printf("res 的值 %d\n", res) } 输出: a 的类型 func(int, int) int res 的值 3
-
为了简化数据定义,Go支持自定义数据类型。相当于一个别名
比如:type myInt int //这时myInt就等价于int来使用了
-
Go函数支持对返回值命名
-
使用
_
标识符时表示忽略该值,可以用作占位符 -
Go支持可变参数。这里的可变参数实际上是slice切片,通过 args[index]的方式来访问各个值
package main import ( "fmt" ) func getSum(num ...int) int { sum := 0 for i := 0; i < len(num); i++ { sum += num[i] } return sum } func main() { sum := getSum(1, 2, 3, 4) fmt.Println(sum) } 输出: 10
init()函数
每一个源文件都可以包含一个init()函数,该函数会在main函数执行前,被Go运行框架调用。
package main
import (
"fmt"
)
func init() {
fmt.Println("init()...")
}
func main() {
fmt.Println("main()...")
}
输出:
init()...
main()...
- 如果一个文件同时包含全局变量定义、init函数和main函数,那么执行的顺序是 :
全局变量定义->init函数->main函数
- init()函数最主要的作用是完成一些初始化的工作
匿名函数
使用方式:
- 在定义匿名函数时就直接调用
- 将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数
package main
import (
"fmt"
)
func main() {
// 求两数之和
// 匿名函数方式1
res1 := func(n1, n2 int) int {
return n1 + n2
}(10, 20)
fmt.Println("匿名函数方式1...res1 = ", res1)
// 匿名函数方式2
func1 := func(n1, n2 int) int {
return n1 + n2
}
res2 := func1(10, 20)
fmt.Println("匿名函数方式2...res2 = ", res2)
}
输出:
匿名函数方式1...res1 = 30
匿名函数方式2...res2 = 30
闭包
闭包就是第一个函数和与其相关的引用环境组合的一个整体(实体)。
现在开始通过例子来说明闭包:
func incr() func() int {
var x int
return func() int {
x++
return x
}
}
调用这个函数会返回一个函数变量。
i := incr()
:通过把这个函数变量赋值给 i
,i
就成为了一个闭包。
所以 i
保存着对 x
的引用,可以想象 i 中有着一个指针指向 x 或 i 中有 x 的地址。
由于 i
有着指向 x
的指针,所以可以修改 x
,且保持着状态:
println(i()) // 1
println(i()) // 2
println(i()) // 3
也就是说,x
逃逸了,它的生命周期没有随着它的作用域结束而结束。
但是这段代码却不会递增:
println(incr()()) // 1
println(incr()()) // 1
println(incr()()) // 1
这是因为这里调用了三次 incr()
,返回了三个闭包,这三个闭包引用着三个不同的 x
,它们的状态是各自独立的。