GO语言基础笔记(二):控制结构与函数

发布时间:2023年12月27日

1. 控制结构

1.1 if-else 结构
  • 基本形式if 条件判断后跟着一个代码块。如果条件为真,则执行该代码块。
  • else 语句:紧随 if 代码块后面,当 if 条件不成立时执行。
  • else if:可以在 ifelse 之间添加更多的条件判断。
package main

import (
	"fmt"
)

func main() {
	score := 85 // 假设这是一个成绩

	// 使用 if 判断成绩是否优秀
	if score >= 90 {
		fmt.Println("成绩优秀,等级:A")
	} else if score >= 80 {
		// 当成绩不满足第一个 if 条件(即小于90),但满足 else if 条件时执行
		fmt.Println("成绩良好,等级:B")
	} else if score >= 70 {
		fmt.Println("成绩合格,等级:C")
	} else if score >= 60 {
		fmt.Println("成绩及格,等级:D")
	} else {
		// 当所有其他条件都不满足时执行 else 块
		fmt.Println("成绩不及格,等级:F")
	}
}
  1. 条件清晰:每个ifelse if块的条件应该是互斥的,这样可以防止重复判断。
  2. 顺序安排:将最有可能发生的条件放在前面,可以提高代码效率。
  3. 避免嵌套过深:尽量减少if-else的嵌套深度,以保持代码的可读性。
  4. 条件简化:在条件判断中使用适当的逻辑运算符来简化表达式。
1.2 switch 结构
  • 基本用法switch 后跟一个表达式,然后是多个 case 分支。每个 case 后跟着要比较的值和执行的代码块。
  • 不带表达式的 switch:可以直接在 case 后使用条件表达式。
  • fallthrough 关键字:默认情况下,每个 case 执行完后自动跳出 switch,使用 fallthrough 可以强制执行下一个 case

?

package main

import (
	"fmt"
)

func main() {
	// 示例1:基本用法
	number := 3
	switch number {
	case 1:
		fmt.Println("数字是 1")
	case 2:
		fmt.Println("数字是 2")
	case 3:
		fmt.Println("数字是 3")
	default:
		fmt.Println("数字不是 1、2、3")
	}

	// 示例2:不带表达式的switch
	score := 85
	switch {
	case score >= 90:
		fmt.Println("成绩优秀")
	case score >= 80:
		fmt.Println("成绩良好")
	case score >= 60:
		fmt.Println("成绩合格")
	default:
		fmt.Println("成绩不合格")
	}

	// 示例3:使用fallthrough
	month := 5
	switch month {
	case 3, 4, 5:
		fmt.Println("春季")
		fallthrough
	case 6, 7, 8:
		fmt.Println("夏季")
	case 9, 10, 11:
		fmt.Println("秋季")
	case 12, 1, 2:
		fmt.Println("冬季")
	default:
		fmt.Println("未知的月份")
	}
}

?

  1. 明确case分支:每个case后面跟着一个或多个要比较的值和代码块。这使得代码逻辑清晰易懂。
  2. 使用default:当所有case都不匹配时,执行default分支。这是一个良好的编程习惯,可用于处理异常或未预期的情况。
  3. 不带表达式的switch:在某些情况下,不带表达式的switch可以替代多层嵌套的if-else,使得代码更加清晰。
  4. 谨慎使用fallthroughfallthrough关键字使得控制流穿越到下一个case,即使下一个case的条件不成立也会执行。使用时要非常小心,以避免逻辑错误。
1.3 for 循环
  • 基本结构:包括初始化语句、条件表达式和结束后的操作,格式为 for 初始化; 条件; 后续操作 {}
  • 条件循环:只有条件表达式的 for 循环。
  • 无限循环:省略所有元素的 for 循环将无限循环直到内部有 breakreturn

????????1. 基本的for循环

package main

import (
	"fmt"
)

func main() {
	// 示例1:基本的for循环
	for i := 0; i < 5; i++ {
		fmt.Println("基本循环,当前索引:", i)
	}
}

?????????2. 条件循环

	// 示例2:条件循环
	j := 0
	for j < 5 {
		fmt.Println("条件循环,当前索引:", j)
		j++
	}

????????3. 无限循环?

	// 示例3:无限循环
	k := 0
	for {
		if k == 3 {
			break // 当 k 等于 3 时退出循环
		}
		fmt.Println("无限循环,当前索引:", k)
		k++
	}
}

技巧性总结

  • 明确循环条件:在编写for循环时,始终清晰地定义循环的开始和结束条件。
  • 避免无限循环:在使用无限循环时,务必确保有一个明确的退出条件,以避免程序陷入死循环。
  • 代码简洁:尽量保持循环体内代码的简洁,这有助于提高代码的可读性和可维护性。

2. 函数

2.1 函数定义
  • 基本语法func 函数名(参数列表) (返回值列表) { 函数体 }
  • 参数列表:定义输入的类型和名称。
  • 返回值列表:可以是具名的也可以是非具名的,具名返回值在函数体开始时被自动初始化。
????????基本函数定义
package main

import (
	"fmt"
)

// 无参数,无返回值的函数
func greet() {
	fmt.Println("Hello, Go!")
}

func main() {
	greet() // 调用函数
}
?????????带参数的函数
// 带参数的函数
func add(x int, y int) int {
	return x + y
}

func main() {
	result := add(5, 7) // 调用函数
	fmt.Println("结果:", result)
}
?????????具名返回值
// 具名返回值
func swap(x, y string) (a, b string) {
	a = y
	b = x
	return // 隐式返回a, b
}

func main() {
	a, b := swap("hello", "world")
	fmt.Println(a, b) // 输出:world hello
}
//使用具名返回值可以提高代码的可读性,尤其是在函数有多个返回值时。
????????非具名返回值?
// 非具名返回值
func divide(x, y float64) (float64, error) {
	if y == 0.0 {
		return 0.0, fmt.Errorf("不能除以零")
	}
	return x / y, nil
}

func main() {
	result, err := divide(10.0, 0.0)
	if err != nil {
		fmt.Println("错误:", err)
	} else {
		fmt.Println("结果:", result)
	}
}
  • 清晰的参数和返回值:定义函数时,明确参数类型和返回值类型可以提高代码的可读性和健壮性。
  • 合理使用具名返回值:在函数返回多个值或需要说明返回值意义时使用具名返回值。
  • 错误处理:在可能出现错误的场合,返回一个错误值作为函数的一部分,以便于错误处理。
2.2 函数使用
  • 调用函数:使用函数名和传入相应的参数。
  • 返回值:可以返回一个或多个值。
  • 匿名函数:没有函数名的函数,可以在定义后立即调用。
????????调用普通函数
package main

import (
	"fmt"
)

// 定义一个简单的相加函数
func add(x, y int) int {
	return x + y
}

func main() {
	// 调用函数并处理返回值
	result := add(5, 7)
	fmt.Println("相加结果:", result)
}
?????????处理多个返回值
// 定义一个函数,返回两个值
func divideAndRemainder(x, y int) (int, int) {
	return x / y, x % y
}

func main() {
	// 接收两个返回值
	quotient, remainder := divideAndRemainder(7, 2)
	fmt.Println("商:", quotient, "余数:", remainder)
}
?????????使用匿名函数
func main() {
	// 定义并立即调用匿名函数
	func(msg string) {
		fmt.Println(msg)
	}("Hello, Go!")
}
  • 函数调用的准确性:在调用函数时,确保参数的正确性和返回值的正确处理。
  • 处理多返回值:在函数返回多个值时,可以通过多个变量来接收这些值。
  • 匿名函数的灵活性:匿名函数是一种灵活的工具,可以用于立即执行一些操作,或作为高阶函数的参数。

2.3回调函数
package main

import (
	"fmt"
)

// 定义回调函数类型,这种函数接受一个整数并返回一个整数
type callbackFunc func(int) int

// processSlice 函数接受一个整数切片和一个回调函数
// 它对切片中的每个元素应用回调函数,并返回新的切片
func processSlice(slice []int, callback callbackFunc) []int {
	var result []int
	for _, value := range slice {
		processedValue := callback(value)
		result = append(result, processedValue)
	}
	return result
}

// 具体的回调函数,例如将整数乘以2
func multiplyByTwo(n int) int {
	return n * 2
}

func main() {
	// 定义一个整数切片
	slice := []int{1, 2, 3, 4, 5}

	// 使用 multiplyByTwo 回调函数处理切片
	processedSlice := processSlice(slice, multiplyByTwo)

	// 打印原始和处理后的切片
	fmt.Println("原始切片:", slice)
	fmt.Println("处理后的切片:", processedSlice)
}

?

????????在这个示例中,我们定义了一个事件管理器eventManager,它允许注册回调函数并在事件触发时调用这些函数。?

package main

import (
	"fmt"
)

// 定义回调函数类型
type eventCallback func()

// 事件管理器
type eventManager struct {
	callbacks []eventCallback
}

// 注册事件的回调函数
func (m *eventManager) registerCallback(callback eventCallback) {
	m.callbacks = append(m.callbacks, callback)
}

// 触发事件,调用所有注册的回调函数
func (m *eventManager) triggerEvent() {
	for _, callback := range m.callbacks {
		callback()
	}
}

func main() {
	// 创建事件管理器实例
	manager := eventManager{}

	// 注册一些回调函数
	manager.registerCallback(func() {
		fmt.Println("第一个事件回调被触发")
	})
	manager.registerCallback(func() {
		fmt.Println("第二个事件回调被触发")
	})

	// 触发事件
	manager.triggerEvent()
}

?

?2.3 go的其他函数机制
  1. 多返回值:Go函数可以返回多个值,这在错误处理和数据返回方面非常有用。

  2. 命名返回值:函数可以有命名的返回值,这些返回值在函数开始时就被声明,可以在函数体内直接使用。

  3. 变参函数(Variadic Functions):Go支持变参函数,允许函数接受任意数量的参数。

  4. 匿名函数和闭包(Closures):Go支持匿名函数,这些函数可以定义在其他函数内部,并可以访问外部函数的变量,形成闭包。

  5. 延迟调用(Defer):Go的defer语句会延迟函数的执行直到包含它的函数结束。

  6. 高阶函数(Higher-Order Functions):在Go中,函数可以作为参数传递给其他函数,也可以作为其他函数的返回值。

  7. 方法(Methods):Go允许定义在结构体(或任意类型)上的函数,称为方法。这提供了一种面向对象的方式来处理数据。

  8. 接口(Interfaces):虽然不是直接的函数机制,但接口在Go中用于定义函数的行为契约,为多态和模块化设计提供支持。

  9. 递归函数(Recursive Functions):函数可以调用自身,这是在处理某些算法时非常有用的。

  10. 并发的函数调用(Goroutines):通过goroutines,Go支持在轻量级线程中并发执行函数。

?

文章来源:https://blog.csdn.net/weixin_44120785/article/details/135177020
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。