1.包的引出
需要在文件中调用其它文件定义的函数
在不同的包中可以定义同名 的函数
2.包的本质就是创建不同的文件夹,来存放程序文件
3.包的作用
区分同名的标识符
控制函数、变量的访问范围,即作用域
4.语法
package 包名
import “package path”
5.包的使用入门
// hello.go
package main
import (
"fmt"
"unsafe"
"go_code/project00/utils"
)
func main() {
n1 := 1.2
n2 := 2.3
var operator byte
fmt.Println("plz input the operator")
fmt.Scanf("%c", &operator)
// test
fmt.Printf("Your input is %v, type is %T, it needs %d bytes\n", operator, operator, unsafe.Sizeof(operator))
ans := utils.Cal(n1, n2, operator)
fmt.Printf("answer is %.2f", ans)
}
// utils.go
package utils
import "fmt"
//首字母大写,该函数可以导出
func Cal(n1 float64, n2 float64, operator byte) float64 {
var res float64
switch operator {
case '+':
res = n1 + n2
case '-':
res = n1 - n2
default:
fmt.Println("ERROR")
}
return res
}
6.文件的包名通常与文件所在的folder一致
7.package指令在第一行,然后import
8.import包的时候,路径从$GOPATH的src下开始,不带src,编译器自动从src下引入
9.import时可以给包取别名,写在路径前面
原来的名字就不好使了
10.同一个包下,不能有相同的函数名
11.如果要编译成一个可执行文件,需要把包声明为main,package main
如果写的是一个库,包名可以自定义
12.编译时需要编译main包所在的文件夹
编译的指令在项目目录下,不用带src
go build go_code\project00\main
在$GOPATH目录下可以指定名字和目录
go build -o bin\my.exe go_code\project00\main
13.内存分配
基本数据类型通常分配在栈区(编译器存在逃逸分析)
引用数据类型通常分配在堆区
代码区
14.函数可以返回多个值
返回和差
// hello.go
package main
import (
"fmt"
"go_code/project00/utils"
)
func main() {
n1 := 1
n2 := 2
// fmt.Println("plz input the operator")
res1, res2 := utils.Cal(n1, n2)
fmt.Printf("answer is %v, %v", res1, res2)
}
// utils.go
package utils
//首字母大写,该函数可以导出
func Cal(n1 int, n2 int) (int, int) {
sub := n1 - n2
sum := n1 + n2
return sum, sub
}
15.go不支持重载
16.go中,函数也是一种数据类型,可以赋值给一个变量,该变量是一个函数类型的变量。通过该变量可以对函数调用
package main
import (
"fmt"
)
func fibo(n int) int {
if n < 3 {
return 1
}
return fibo(n - 1) + fibo(n - 2)
}
func main() {
a := fibo
fmt.Printf("type of a is %T, type of fibo is %T\n", a, fibo)
fmt.Println("input n")
var n int
fmt.Scanln(&n)
fmt.Println(a(n))// 1 1 2 3 5
}
17.go中,函数可以作为形参
package main
import (
"fmt"
)
func fibo(n int) int {
if n < 3 {
return 1
}
return fibo(n - 1) + fibo(n - 2)
}
func myFun(funVar func(int) int, num int) int {
return funVar(num);
}
func main() {
a := fibo
fmt.Printf("type of a is %T, type of fibo is %T\n", a, fibo)
fmt.Println("input n")
var n int
fmt.Scanln(&n)
fmt.Println(myFun(fibo, n))// 1 1 2 3 5
}
18。go支持自定义数据类型
type 自定义类型名 类型
相当于起别名
// 给int取了别名,但go认为int与myInt是不同的类型
type myInt int
var num1 myInt
var num2 int
num1 = 40
num2 = int(num1) // 需要显式转换
fmt.Println(num1, num2)
package main
import (
"fmt"
)
type myFunType func(int, int) int
func getSum(n1 int, n2 int) int {
return n1 + n2
}
func myFun(funVar myFunType, n1 int, n2 int) int {
return funVar(n1, n2)
}
func main() {
fmt.Println(myFun(getSum, 2, 4))
}
19.支持对函数返回值命名
func getSumAndSub(n1 int, n2 int) (sum int, sub int) {
sum = n1 + n2
sub = n1 - n2
return
}
函数在定义时就定义了返回值
20.go支持可变参数
slice切片是一个动态数组
这种报错是忘了返回
# command-line-arguments
.\hello.go:12:1: missing return at end of function
package main
import (
"fmt"
)
// 可变参数的使用
func sum(n1 int, args... int) int {
sum := n1
// args traversal
for i := 0; i < len(args); i++ {
sum += args[i] // 取出args的ith值
}
return sum
}
func main() {
fmt.Println(sum(10))
fmt.Println(sum(1, 2, 3, 4, 6))
}
可变参数只能放在形参列表的最后一个
21.每个源文件都可以包含一个init函数,该函数在main函数之前,被go运行框架调用,也就是initial会在main之前被调用。
22.如果一个文件同时有全局变量定义,init,main
执行的流程是变量定义=>init=>main
package main
import "fmt"
var age = test()
func test() int {
fmt.Println("test()")
return 90
}
func init() {
fmt.Println("init()")
}
func main() {
fmt.Println("main age=", age)
}
23.执行顺序
24.匿名函数
如果某个函数希望只用一次,可以用匿名
匿名函数 也可以多次调用
匿名函数可以在定义时调用
// 接收结果
res1 := func (n1 int, n2 int) int {
return n1 + n2
}(10, 2) // 在定义时完成调用
fmt.Println(res1)
将匿名函数赋给变量,通过变量调用
// a是一个函数变量
a := func (n1 int, n2 int) int {
return n1 - n2
}
// a可以反复调用
fmt.Println(a(20, 44))
将匿名函数赋给全局变量,成为全局匿名函数,
var (
age = test()
//前面写了var 不用写:
// fun1不用大写,全局变量
fun1 = func (n1 int, n2 int) int {
return n1 * n2
}
)
func test() int {
fmt.Println("test()")
return 90
}
func main() {
fmt.Println("main age=", age)
fmt.Println(utils.Age, utils.Name)
fmt.Println(fun1(3, 42))
}