怎么定义一个函数呢?
练习:我们来实现一个求加减的函数?
func getSumSub(x, y int) (int, sub int) { // 第一个返回值是int类型,第二个是返回整型的sub变量
sub = x - y
return x + y, sub
}
相同类型的参数是可以合并类型的。比如 x int, y int 参数,可以简写为 x, y int
go中,支持多个返回值,并且还支持变量返回值。
函数必须给参数,或返回值吗?
不是的,参数,返回值 可以都不给。
func say() {
fmt.Println("11")
}
如果参数个数不确定怎么办?
func getSum(x int, y ...int) int { // 这种参数本质是切片,注意:上面的可变参数,一般要放固定参数后边
sum := x
for _, v := range y {
sum += v
}
return sum
}
r := getSum()
r := getSum(10, 20, 30)
怎么接收多个返回值?
func calc(x, y int) (int, int) {
return x + y, x - y
}
// 两个都接收
sum, sub := calc(1, 12)
// 只接收第一个
sum, _ := calc(1, 12)
// 只接收第二个
_, sub := calc(1, 2)
返回值命名用变量是什么意思?
func calc(x, y int) (sum, sub int) { // 可以看到返回值是两个整型变量 sum,sub
sum = x + y // 仔细观察,sum变量是可以直接赋值的,因为返回值声明中,已经定义了该变量
sub = x - y
return
}
返回值是切片类型,如果没有要返回的值,一定要返回一个空切片吗?
不是的,我们可以直接返回 nil,go编译器会自动处理为空切片。
func some(x string) []int {
if x == "" {
return nil // []int{}
} else {
s := make([]int, len(x))
for i := 0; i < len(x); i++ {
s[i] = int(x[i])
}
return s
}
}
函数外的变量,函数里面可以访问吗?
可以,这种变量处于全局作用域,函数内可以直接访问,其生命周期就是程序的整个运行周期。
var globalN int64 = 0 // 全局计数器,注意:在函数外,声明变量必须得用var关键字了。
func incrN() {
globalN++
}
func main() {
incrN()
incrN()
fmt.Printf("%d\n", globalN)
}
有哪些局部变量?
1、函数内定义的变量。
2、如果局部变量和全局重名,则局部先生效。
var a int = 0
func test() {
a := 10 // 局部变量生效
}
3、if,for,switch 等语句块中定义的变量,它们的作用域就是当前的语句块内。
if x > 0 {
z := 100
}
fmt.Println(z) // 无法访问
for i := 0; i < 10; i++ {
fmt.Println(i)
}
fmt.Println(i) // 无法访问
函数是一种数据类型吗?
是的
func add(x, y int) int {
return x + y
}
f := add
fmt.Printf("%T\n", f) // func(int, int) int
可以自定义一个函数类型吗?
可以,type关键字可以定义自己的数据类型。
type calc func(int, int) int
func add(x, y int) int{
return x + y
}
func main() {
var c calc
c = add
fmt.Printf("%T\n", c) // main.calc
}
函数作为参数有什么意义?
其实可以理解为一种控制反转,依赖注入的方式。使原本的函数不用改动,就可以支持多行为。
type sortFunc func(a, b int) bool
func sortInts(ints []int, fn sortFunc) {
sort.Slice(ints, func(i, j int) bool {
return fn(ints[i], ints[j])
})
}
func asc(a, b int) bool {
return a < b
}
func desc(a, b int) bool {
return a > b
}
func main() {
nums := []int{5, 3, 4, 1, 2}
sortInts(nums, asc)
fmt.Println(nums)
sortInts(nums, desc)
fmt.Println(nums)
}
函数作为返回值有什么意义?
方便实现闭包,回调,工厂函数等特性
func add(x, y int) int {
return x + y
}
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "-":
return func(x, y int) int { // 可以直接写匿名函数
return x - y
}, nil
default:
err := errors.New("无法识别的操作符")
return nil, err
}
}
func main() {
r, err := do("+")
if err != nil {
fmt.Println(err)
}
fmt.Println(r(1, 2))
}
看个简单的工厂模式
func createMul(factor int) func(int) int {
return func(value int) int {
return value * factor
}
}
func main() {
double := createMul(2)
trible := createMul(3)
fmt.Println(double(5), trible(5))
}
什么是匿名函数,有什么作用?
就是没有函数名称的函数,可以直接访问到,它外面定义的变量,一般用于实现闭包,回调等等。
add := func(x, y int) {
fmt.Println(x + y)
}
add(1, 2)
func(x, y int) {
fmt.Println(x - y)
}(1, 2)
什么是闭包?
引用环境 + 匿名函数 = 闭包
func add() func(int) int {
var x int
return func(y int) int {
x += y
return x
}
}
func main() {
f := add()
fmt.Println(f(10))
fmt.Println(f(20))
}
func add(x int) func(int) int {
return func(y int) int {
x += y
return x
}
}
func main() {
f := add(10)
fmt.Println(f(10))
fmt.Println(f(20))
}
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
func main() {
jpgFunc := makeSuffixFunc(".jpg")
txtFunc := makeSuffixFunc(".txt")
fmt.Println(jpgFunc("test")) // test.jpg
fmt.Println(txtFunc("test")) // test.txt
}
func calc(base int) (func(int) int, func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add, sub
}
func main() {
f1, f2 := calc(10)
fmt.Println(f1(1), f2(2)) // 11 9
fmt.Println(f1(3), f2(4)) // 12 8
}
什么是 defer ?
一种延迟执行机制。
defer的执行时机?
多个defer的执行顺序?
倒序,先进后出
注意:defer注册的延迟执行函数,函数的参数都有确定其值。
猜猜下面的代码的执行结果:
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println("end")
func f1() int {
x := 5
defer func() {
x++
}()
return x
}
fmt.Println(f1()) // 5
func f2() (x int) {
defer func() {
x++
}()
return 5
}
fmt.Println(f2()) // 6
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
}
fmt.Println(f3()) // 5
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5
}
fmt.Println(f4()) // 5
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
有哪些常用的内置函数?
close 关闭channel
len 求string,array,slice,map,channel的长度
new 分配内存,初始化值类型变量,返回指针
make 分配内存,初始化chan,map,slice,返回数据本身
append 追加元素到slice
panic,recover 是干什么的?
panic 可以理解为抛出异常
recover 可以理解为捕获异常
panic + defer + recover = try … catch
func funcA() {
fmt.Println("func A")
}
func funcB() {
defer func() {
err := recover()
if err != nil {
fmt.Println("recover in B", err)
}
}()
panic("panic in B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}
练习题
/*
你有50枚金币,需要分配给以下几个人:Matthew,Sarah,Augustus,Heidi,Emilie,Peter,Giana,Adriano,Aaron,Elizabeth。
分配规则如下:
a. 名字中每包含1个'e'或'E'分1枚金币
b. 名字中每包含1个'i'或'I'分2枚金币
c. 名字中每包含1个'o'或'O'分3枚金币
d: 名字中每包含1个'u'或'U'分4枚金币
写一个程序,计算每个用户分到多少金币,以及最后剩余多少金币?
程序结构如下,请实现 ‘dispatchCoin’ 函数
*/
var (
coins = 50
users = []string{
"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
}
distribution = make(map[string]int, len(users))
)
func main() {
left := dispatchCoin()
fmt.Println("剩下:", left)
}
func dispatchCoin() int {
for _, user := range users {
for i := 0; i < len(user); i++ {
c := fmt.Sprintf("%c", user[i])
if c == "e" || c == "E" {
distribution[user] += 1
} else if c == "i" || c == "I" {
distribution[user] += 2
} else if c == "o" || c == "O" {
distribution[user] += 3
} else if c == "u" || c == "U" {
distribution[user] += 4
}
}
}
totalGlod := 0
for _, n := range distribution {
totalGlod += n
}
return coins - totalGlod
}
大佬好认真
谢谢您的评论。
大佬入门看的什么书和视频啊 推荐一下。我在leranku看到的。
https://learnku.com/go/docs 这里就有的,然后书籍的话有 go语言编程之旅,go圣经,视频的话,如果是小白,可以选择一些靠谱的机构的课程,比如慕课实战系列的,51cto,黑马,尚硅谷。基本看完,问题不大了。