带着问题学go ~~~ 函数

怎么定义一个函数呢?

练习:我们来实现一个求加减的函数?

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
}

评论

  1. 当事男主
    4 周前
    2024-9-14 16:17:29

    大佬好认真

    • 博主
      当事男主
      4 周前
      2024-9-14 22:56:42

      谢谢您的评论。

  2. 当事男主
    4 周前
    2024-9-14 16:32:54

    大佬入门看的什么书和视频啊 推荐一下。我在leranku看到的。

    • 博主
      当事男主
      4 周前
      2024-9-14 22:59:47

      https://learnku.com/go/docs 这里就有的,然后书籍的话有 go语言编程之旅,go圣经,视频的话,如果是小白,可以选择一些靠谱的机构的课程,比如慕课实战系列的,51cto,黑马,尚硅谷。基本看完,问题不大了。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇