初始提交
This commit is contained in:
722
golang-learning/03-functions/01-basic-functions.go
Normal file
722
golang-learning/03-functions/01-basic-functions.go
Normal file
@@ -0,0 +1,722 @@
|
||||
/*
|
||||
01-basic-functions.go - Go 语言基础函数详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握函数的基本语法和定义
|
||||
2. 理解函数参数和返回值
|
||||
3. 学会函数的调用方式
|
||||
4. 了解函数的作用域规则
|
||||
5. 掌握函数的实际应用
|
||||
|
||||
知识点:
|
||||
- 函数定义语法
|
||||
- 参数传递(值传递)
|
||||
- 返回值
|
||||
- 函数调用
|
||||
- 函数作为值
|
||||
- 匿名函数
|
||||
- 递归函数
|
||||
- 函数作用域
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言基础函数详解 ===\n")
|
||||
|
||||
// 演示基本函数定义和调用
|
||||
demonstrateBasicFunctions()
|
||||
|
||||
// 演示函数参数
|
||||
demonstrateFunctionParameters()
|
||||
|
||||
// 演示函数返回值
|
||||
demonstrateFunctionReturns()
|
||||
|
||||
// 演示函数作为值
|
||||
demonstrateFunctionAsValue()
|
||||
|
||||
// 演示匿名函数
|
||||
demonstrateAnonymousFunctions()
|
||||
|
||||
// 演示递归函数
|
||||
demonstrateRecursiveFunctions()
|
||||
|
||||
// 演示函数作用域
|
||||
demonstrateFunctionScope()
|
||||
|
||||
// 演示实际应用示例
|
||||
demonstratePracticalExamples()
|
||||
}
|
||||
|
||||
// demonstrateBasicFunctions 演示基本函数定义和调用
|
||||
func demonstrateBasicFunctions() {
|
||||
fmt.Println("1. 基本函数定义和调用:")
|
||||
|
||||
// 调用无参数无返回值的函数
|
||||
fmt.Printf(" 调用无参数无返回值的函数:\n")
|
||||
sayHello()
|
||||
|
||||
// 调用有参数无返回值的函数
|
||||
fmt.Printf(" 调用有参数无返回值的函数:\n")
|
||||
greetPerson("Alice")
|
||||
greetPerson("Bob")
|
||||
|
||||
// 调用有参数有返回值的函数
|
||||
fmt.Printf(" 调用有参数有返回值的函数:\n")
|
||||
result := add(10, 20)
|
||||
fmt.Printf(" add(10, 20) = %d\n", result)
|
||||
|
||||
// 直接在表达式中使用函数调用
|
||||
fmt.Printf(" add(5, 7) * 2 = %d\n", add(5, 7)*2)
|
||||
|
||||
// 函数调用作为参数
|
||||
fmt.Printf(" add(add(1, 2), add(3, 4)) = %d\n", add(add(1, 2), add(3, 4)))
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFunctionParameters 演示函数参数
|
||||
func demonstrateFunctionParameters() {
|
||||
fmt.Println("2. 函数参数:")
|
||||
|
||||
// 单个参数
|
||||
fmt.Printf(" 单个参数:\n")
|
||||
square := calculateSquare(5)
|
||||
fmt.Printf(" calculateSquare(5) = %d\n", square)
|
||||
|
||||
// 多个参数
|
||||
fmt.Printf(" 多个参数:\n")
|
||||
area := calculateRectangleArea(4, 6)
|
||||
fmt.Printf(" calculateRectangleArea(4, 6) = %d\n", area)
|
||||
|
||||
// 相同类型的多个参数
|
||||
fmt.Printf(" 相同类型的多个参数:\n")
|
||||
max := findMax(15, 8, 23, 4, 19)
|
||||
fmt.Printf(" findMax(15, 8, 23, 4, 19) = %d\n", max)
|
||||
|
||||
// 不同类型的参数
|
||||
fmt.Printf(" 不同类型的参数:\n")
|
||||
info := formatPersonInfo("Charlie", 25, 175.5)
|
||||
fmt.Printf(" %s\n", info)
|
||||
|
||||
// 参数是值传递
|
||||
fmt.Printf(" 参数是值传递(不会修改原变量):\n")
|
||||
x := 10
|
||||
fmt.Printf(" 修改前: x = %d\n", x)
|
||||
tryToModify(x)
|
||||
fmt.Printf(" 修改后: x = %d (未改变)\n", x)
|
||||
|
||||
// 传递切片(引用类型)
|
||||
fmt.Printf(" 传递切片(引用类型):\n")
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
fmt.Printf(" 修改前: %v\n", numbers)
|
||||
modifySlice(numbers)
|
||||
fmt.Printf(" 修改后: %v (已改变)\n", numbers)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFunctionReturns 演示函数返回值
|
||||
func demonstrateFunctionReturns() {
|
||||
fmt.Println("3. 函数返回值:")
|
||||
|
||||
// 单个返回值
|
||||
fmt.Printf(" 单个返回值:\n")
|
||||
length := getStringLength("Hello, World!")
|
||||
fmt.Printf(" 字符串长度: %d\n", length)
|
||||
|
||||
// 多个返回值
|
||||
fmt.Printf(" 多个返回值:\n")
|
||||
quotient, remainder := divide(17, 5)
|
||||
fmt.Printf(" 17 ÷ 5 = %d 余 %d\n", quotient, remainder)
|
||||
|
||||
// 命名返回值
|
||||
fmt.Printf(" 命名返回值:\n")
|
||||
min, max := findMinMax([]int{3, 7, 1, 9, 4, 6})
|
||||
fmt.Printf(" 数组 [3, 7, 1, 9, 4, 6] 的最小值: %d, 最大值: %d\n", min, max)
|
||||
|
||||
// 忽略某些返回值
|
||||
fmt.Printf(" 忽略某些返回值:\n")
|
||||
_, rem := divide(20, 3)
|
||||
fmt.Printf(" 20 ÷ 3 的余数: %d\n", rem)
|
||||
|
||||
// 返回函数
|
||||
fmt.Printf(" 返回函数:\n")
|
||||
multiplier := getMultiplier(3)
|
||||
result := multiplier(10)
|
||||
fmt.Printf(" 3倍数函数应用于10: %d\n", result)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFunctionAsValue 演示函数作为值
|
||||
func demonstrateFunctionAsValue() {
|
||||
fmt.Println("4. 函数作为值:")
|
||||
|
||||
// 将函数赋值给变量
|
||||
fmt.Printf(" 将函数赋值给变量:\n")
|
||||
var operation func(int, int) int
|
||||
operation = add
|
||||
fmt.Printf(" operation = add; operation(5, 3) = %d\n", operation(5, 3))
|
||||
|
||||
operation = multiply
|
||||
fmt.Printf(" operation = multiply; operation(5, 3) = %d\n", operation(5, 3))
|
||||
|
||||
// 函数作为参数
|
||||
fmt.Printf(" 函数作为参数:\n")
|
||||
numbers := []int{1, 2, 3, 4, 5}
|
||||
|
||||
result1 := applyOperation(numbers, double)
|
||||
fmt.Printf(" 应用 double 函数: %v -> %v\n", numbers, result1)
|
||||
|
||||
result2 := applyOperation(numbers, square)
|
||||
fmt.Printf(" 应用 square 函数: %v -> %v\n", numbers, result2)
|
||||
|
||||
// 函数切片
|
||||
fmt.Printf(" 函数切片:\n")
|
||||
operations := []func(int, int) int{add, subtract, multiply}
|
||||
operationNames := []string{"加法", "减法", "乘法"}
|
||||
|
||||
a, b := 12, 4
|
||||
for i, op := range operations {
|
||||
result := op(a, b)
|
||||
fmt.Printf(" %s: %d %s %d = %d\n", operationNames[i], a, getOperatorSymbol(i), b, result)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAnonymousFunctions 演示匿名函数
|
||||
func demonstrateAnonymousFunctions() {
|
||||
fmt.Println("5. 匿名函数:")
|
||||
|
||||
// 基本匿名函数
|
||||
fmt.Printf(" 基本匿名函数:\n")
|
||||
result := func(x, y int) int {
|
||||
return x*x + y*y
|
||||
}(3, 4)
|
||||
fmt.Printf(" 匿名函数计算 3² + 4² = %d\n", result)
|
||||
|
||||
// 将匿名函数赋值给变量
|
||||
fmt.Printf(" 将匿名函数赋值给变量:\n")
|
||||
isEven := func(n int) bool {
|
||||
return n%2 == 0
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
fmt.Printf(" %d 是偶数: %t\n", i, isEven(i))
|
||||
}
|
||||
|
||||
// 匿名函数作为参数
|
||||
fmt.Printf(" 匿名函数作为参数:\n")
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
evenNumbers := filter(numbers, func(n int) bool {
|
||||
return n%2 == 0
|
||||
})
|
||||
fmt.Printf(" 偶数: %v\n", evenNumbers)
|
||||
|
||||
largeNumbers := filter(numbers, func(n int) bool {
|
||||
return n > 5
|
||||
})
|
||||
fmt.Printf(" 大于5的数: %v\n", largeNumbers)
|
||||
|
||||
// 匿名函数闭包
|
||||
fmt.Printf(" 匿名函数闭包:\n")
|
||||
counter := func() func() int {
|
||||
count := 0
|
||||
return func() int {
|
||||
count++
|
||||
return count
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Printf(" 计数器调用1: %d\n", counter())
|
||||
fmt.Printf(" 计数器调用2: %d\n", counter())
|
||||
fmt.Printf(" 计数器调用3: %d\n", counter())
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateRecursiveFunctions 演示递归函数
|
||||
func demonstrateRecursiveFunctions() {
|
||||
fmt.Println("6. 递归函数:")
|
||||
|
||||
// 阶乘函数
|
||||
fmt.Printf(" 阶乘函数:\n")
|
||||
for i := 0; i <= 5; i++ {
|
||||
fact := factorial(i)
|
||||
fmt.Printf(" %d! = %d\n", i, fact)
|
||||
}
|
||||
|
||||
// 斐波那契数列
|
||||
fmt.Printf(" 斐波那契数列:\n")
|
||||
fmt.Printf(" 前10个斐波那契数: ")
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Printf("%d ", fibonacci(i))
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
// 二分查找
|
||||
fmt.Printf(" 二分查找:\n")
|
||||
sortedArray := []int{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}
|
||||
target := 7
|
||||
|
||||
index := binarySearch(sortedArray, target, 0, len(sortedArray)-1)
|
||||
if index != -1 {
|
||||
fmt.Printf(" 在数组 %v 中找到 %d,索引: %d\n", sortedArray, target, index)
|
||||
} else {
|
||||
fmt.Printf(" 在数组 %v 中未找到 %d\n", sortedArray, target)
|
||||
}
|
||||
|
||||
// 计算数字各位数之和
|
||||
fmt.Printf(" 计算数字各位数之和:\n")
|
||||
number := 12345
|
||||
digitSum := sumOfDigits(number)
|
||||
fmt.Printf(" %d 的各位数之和: %d\n", number, digitSum)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateFunctionScope 演示函数作用域
|
||||
func demonstrateFunctionScope() {
|
||||
fmt.Println("7. 函数作用域:")
|
||||
|
||||
// 全局变量
|
||||
fmt.Printf(" 全局变量: globalVar = %s\n", globalVar)
|
||||
|
||||
// 局部变量
|
||||
fmt.Printf(" 局部变量:\n")
|
||||
localVar := "这是局部变量"
|
||||
fmt.Printf(" localVar = %s\n", localVar)
|
||||
|
||||
// 函数内部的作用域
|
||||
fmt.Printf(" 函数内部的作用域:\n")
|
||||
testScope()
|
||||
|
||||
// 参数作用域
|
||||
fmt.Printf(" 参数作用域:\n")
|
||||
testParameterScope("参数值")
|
||||
|
||||
// 变量遮蔽
|
||||
fmt.Printf(" 变量遮蔽:\n")
|
||||
testVariableShadowing()
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalExamples 演示实际应用示例
|
||||
func demonstratePracticalExamples() {
|
||||
fmt.Println("8. 实际应用示例:")
|
||||
|
||||
// 示例1: 数据处理函数
|
||||
fmt.Printf(" 示例1 - 学生成绩处理:\n")
|
||||
scores := []int{85, 92, 78, 96, 88, 73, 91, 87}
|
||||
|
||||
avg := calculateAverage(scores)
|
||||
fmt.Printf(" 平均分: %.2f\n", avg)
|
||||
|
||||
grade := getLetterGrade(avg)
|
||||
fmt.Printf(" 等级: %s\n", grade)
|
||||
|
||||
passCount := countPassingScores(scores, 80)
|
||||
fmt.Printf(" 80分以上人数: %d/%d\n", passCount, len(scores))
|
||||
|
||||
// 示例2: 字符串处理函数
|
||||
fmt.Printf(" 示例2 - 文本处理:\n")
|
||||
text := "Hello, World! This is a test."
|
||||
|
||||
wordCount := countWords(text)
|
||||
fmt.Printf(" 文本: \"%s\"\n", text)
|
||||
fmt.Printf(" 单词数: %d\n", wordCount)
|
||||
|
||||
reversed := reverseString(text)
|
||||
fmt.Printf(" 反转: \"%s\"\n", reversed)
|
||||
|
||||
isPalindrome := checkPalindrome("racecar")
|
||||
fmt.Printf(" \"racecar\" 是回文: %t\n", isPalindrome)
|
||||
|
||||
// 示例3: 数学计算函数
|
||||
fmt.Printf(" 示例3 - 几何计算:\n")
|
||||
|
||||
circleArea := calculateCircleArea(5.0)
|
||||
fmt.Printf(" 半径5的圆面积: %.2f\n", circleArea)
|
||||
|
||||
triangleArea := calculateTriangleArea(3.0, 4.0, 5.0)
|
||||
fmt.Printf(" 边长3,4,5的三角形面积: %.2f\n", triangleArea)
|
||||
|
||||
distance := calculateDistance(0, 0, 3, 4)
|
||||
fmt.Printf(" 点(0,0)到点(3,4)的距离: %.2f\n", distance)
|
||||
|
||||
// 示例4: 数据验证函数
|
||||
fmt.Printf(" 示例4 - 数据验证:\n")
|
||||
|
||||
emails := []string{
|
||||
"user@example.com",
|
||||
"invalid-email",
|
||||
"test@domain.org",
|
||||
}
|
||||
|
||||
for _, email := range emails {
|
||||
isValid := validateEmail(email)
|
||||
fmt.Printf(" 邮箱 \"%s\" 有效: %t\n", email, isValid)
|
||||
}
|
||||
|
||||
phone := "138-1234-5678"
|
||||
isValidPhone := validatePhoneNumber(phone)
|
||||
fmt.Printf(" 电话 \"%s\" 有效: %t\n", phone, isValidPhone)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// ========== 函数定义 ==========
|
||||
|
||||
// 全局变量
|
||||
var globalVar = "全局变量"
|
||||
|
||||
// 无参数无返回值的函数
|
||||
func sayHello() {
|
||||
fmt.Printf(" Hello, World!\n")
|
||||
}
|
||||
|
||||
// 有参数无返回值的函数
|
||||
func greetPerson(name string) {
|
||||
fmt.Printf(" Hello, %s!\n", name)
|
||||
}
|
||||
|
||||
// 有参数有返回值的函数
|
||||
func add(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
// 单个参数函数
|
||||
func calculateSquare(n int) int {
|
||||
return n * n
|
||||
}
|
||||
|
||||
// 多个参数函数
|
||||
func calculateRectangleArea(width, height int) int {
|
||||
return width * height
|
||||
}
|
||||
|
||||
// 相同类型多个参数函数
|
||||
func findMax(numbers ...int) int {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
max := numbers[0]
|
||||
for _, num := range numbers {
|
||||
if num > max {
|
||||
max = num
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// 不同类型参数函数
|
||||
func formatPersonInfo(name string, age int, height float64) string {
|
||||
return fmt.Sprintf("姓名: %s, 年龄: %d, 身高: %.1fcm", name, age, height)
|
||||
}
|
||||
|
||||
// 尝试修改参数(值传递)
|
||||
func tryToModify(x int) {
|
||||
x = 100
|
||||
fmt.Printf(" 函数内部: x = %d\n", x)
|
||||
}
|
||||
|
||||
// 修改切片
|
||||
func modifySlice(slice []int) {
|
||||
if len(slice) > 0 {
|
||||
slice[0] = 999
|
||||
}
|
||||
}
|
||||
|
||||
// 单个返回值函数
|
||||
func getStringLength(s string) int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// 多个返回值函数
|
||||
func divide(a, b int) (int, int) {
|
||||
return a / b, a % b
|
||||
}
|
||||
|
||||
// 命名返回值函数
|
||||
func findMinMax(numbers []int) (min, max int) {
|
||||
if len(numbers) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
min, max = numbers[0], numbers[0]
|
||||
for _, num := range numbers {
|
||||
if num < min {
|
||||
min = num
|
||||
}
|
||||
if num > max {
|
||||
max = num
|
||||
}
|
||||
}
|
||||
return // 自动返回命名的返回值
|
||||
}
|
||||
|
||||
// 返回函数的函数
|
||||
func getMultiplier(factor int) func(int) int {
|
||||
return func(x int) int {
|
||||
return x * factor
|
||||
}
|
||||
}
|
||||
|
||||
// 基本运算函数
|
||||
func multiply(a, b int) int {
|
||||
return a * b
|
||||
}
|
||||
|
||||
func subtract(a, b int) int {
|
||||
return a - b
|
||||
}
|
||||
|
||||
// 应用操作函数
|
||||
func applyOperation(numbers []int, operation func(int) int) []int {
|
||||
result := make([]int, len(numbers))
|
||||
for i, num := range numbers {
|
||||
result[i] = operation(num)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 操作函数
|
||||
func double(x int) int {
|
||||
return x * 2
|
||||
}
|
||||
|
||||
func square(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
// 获取运算符符号
|
||||
func getOperatorSymbol(index int) string {
|
||||
symbols := []string{"+", "-", "×"}
|
||||
if index < len(symbols) {
|
||||
return symbols[index]
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
// 过滤函数
|
||||
func filter(numbers []int, predicate func(int) bool) []int {
|
||||
var result []int
|
||||
for _, num := range numbers {
|
||||
if predicate(num) {
|
||||
result = append(result, num)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 递归函数:阶乘
|
||||
func factorial(n int) int {
|
||||
if n <= 1 {
|
||||
return 1
|
||||
}
|
||||
return n * factorial(n-1)
|
||||
}
|
||||
|
||||
// 递归函数:斐波那契
|
||||
func fibonacci(n int) int {
|
||||
if n <= 1 {
|
||||
return n
|
||||
}
|
||||
return fibonacci(n-1) + fibonacci(n-2)
|
||||
}
|
||||
|
||||
// 递归函数:二分查找
|
||||
func binarySearch(arr []int, target, left, right int) int {
|
||||
if left > right {
|
||||
return -1
|
||||
}
|
||||
|
||||
mid := (left + right) / 2
|
||||
if arr[mid] == target {
|
||||
return mid
|
||||
} else if arr[mid] > target {
|
||||
return binarySearch(arr, target, left, mid-1)
|
||||
} else {
|
||||
return binarySearch(arr, target, mid+1, right)
|
||||
}
|
||||
}
|
||||
|
||||
// 递归函数:数字各位数之和
|
||||
func sumOfDigits(n int) int {
|
||||
if n < 10 {
|
||||
return n
|
||||
}
|
||||
return n%10 + sumOfDigits(n/10)
|
||||
}
|
||||
|
||||
// 作用域测试函数
|
||||
func testScope() {
|
||||
innerVar := "函数内部变量"
|
||||
fmt.Printf(" innerVar = %s\n", innerVar)
|
||||
|
||||
if true {
|
||||
blockVar := "块级变量"
|
||||
fmt.Printf(" blockVar = %s\n", blockVar)
|
||||
}
|
||||
// blockVar 在这里不可访问
|
||||
}
|
||||
|
||||
func testParameterScope(param string) {
|
||||
fmt.Printf(" 参数 param = %s\n", param)
|
||||
param = "修改后的参数"
|
||||
fmt.Printf(" 修改后 param = %s\n", param)
|
||||
}
|
||||
|
||||
func testVariableShadowing() {
|
||||
x := "外层变量"
|
||||
fmt.Printf(" 外层 x = %s\n", x)
|
||||
|
||||
if true {
|
||||
x := "内层变量" // 遮蔽外层变量
|
||||
fmt.Printf(" 内层 x = %s\n", x)
|
||||
}
|
||||
|
||||
fmt.Printf(" 外层 x = %s (未被修改)\n", x)
|
||||
}
|
||||
|
||||
// 实际应用函数
|
||||
func calculateAverage(scores []int) float64 {
|
||||
if len(scores) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
sum := 0
|
||||
for _, score := range scores {
|
||||
sum += score
|
||||
}
|
||||
return float64(sum) / float64(len(scores))
|
||||
}
|
||||
|
||||
func getLetterGrade(average float64) string {
|
||||
switch {
|
||||
case average >= 90:
|
||||
return "A"
|
||||
case average >= 80:
|
||||
return "B"
|
||||
case average >= 70:
|
||||
return "C"
|
||||
case average >= 60:
|
||||
return "D"
|
||||
default:
|
||||
return "F"
|
||||
}
|
||||
}
|
||||
|
||||
func countPassingScores(scores []int, threshold int) int {
|
||||
count := 0
|
||||
for _, score := range scores {
|
||||
if score >= threshold {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func countWords(text string) int {
|
||||
words := strings.Fields(text)
|
||||
return len(words)
|
||||
}
|
||||
|
||||
func reverseString(s string) string {
|
||||
runes := []rune(s)
|
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||
runes[i], runes[j] = runes[j], runes[i]
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func checkPalindrome(s string) bool {
|
||||
s = strings.ToLower(s)
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
if s[i] != s[j] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func calculateCircleArea(radius float64) float64 {
|
||||
return math.Pi * radius * radius
|
||||
}
|
||||
|
||||
func calculateTriangleArea(a, b, c float64) float64 {
|
||||
// 使用海伦公式
|
||||
s := (a + b + c) / 2
|
||||
return math.Sqrt(s * (s - a) * (s - b) * (s - c))
|
||||
}
|
||||
|
||||
func calculateDistance(x1, y1, x2, y2 float64) float64 {
|
||||
dx := x2 - x1
|
||||
dy := y2 - y1
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
}
|
||||
|
||||
func validateEmail(email string) bool {
|
||||
return strings.Contains(email, "@") && strings.Contains(email, ".")
|
||||
}
|
||||
|
||||
func validatePhoneNumber(phone string) bool {
|
||||
// 简单验证:包含数字和连字符
|
||||
return strings.Contains(phone, "-") && len(phone) >= 10
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 01-basic-functions.go
|
||||
|
||||
学习要点:
|
||||
1. 函数是 Go 程序的基本构建块
|
||||
2. 函数定义语法:func 函数名(参数列表) 返回类型 { 函数体 }
|
||||
3. Go 支持多返回值,这是其特色功能之一
|
||||
4. 参数传递是值传递,但引用类型(切片、映射等)传递的是引用
|
||||
5. 函数可以作为值传递和赋值
|
||||
6. 支持匿名函数和闭包
|
||||
7. 递归函数需要有明确的终止条件
|
||||
|
||||
函数的组成部分:
|
||||
1. func 关键字
|
||||
2. 函数名
|
||||
3. 参数列表(可选)
|
||||
4. 返回类型(可选)
|
||||
5. 函数体
|
||||
|
||||
函数特性:
|
||||
1. 支持多返回值
|
||||
2. 支持命名返回值
|
||||
3. 函数是一等公民(可以作为值)
|
||||
4. 支持匿名函数和闭包
|
||||
5. 支持递归调用
|
||||
|
||||
最佳实践:
|
||||
1. 函数名应该清晰表达功能
|
||||
2. 保持函数简短和专注
|
||||
3. 合理使用多返回值
|
||||
4. 适当使用命名返回值提高可读性
|
||||
5. 避免过深的递归调用
|
||||
6. 考虑函数的副作用
|
||||
|
||||
常见应用场景:
|
||||
1. 代码复用和模块化
|
||||
2. 数据处理和计算
|
||||
3. 输入验证和格式化
|
||||
4. 算法实现
|
||||
5. 业务逻辑封装
|
||||
6. 工具函数库
|
||||
*/
|
774
golang-learning/03-functions/02-multiple-returns.go
Normal file
774
golang-learning/03-functions/02-multiple-returns.go
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
02-multiple-returns.go - Go 语言多返回值详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握多返回值的语法和用法
|
||||
2. 理解命名返回值的优势
|
||||
3. 学会错误处理的惯用模式
|
||||
4. 了解多返回值的实际应用场景
|
||||
5. 掌握返回值的最佳实践
|
||||
|
||||
知识点:
|
||||
- 多返回值语法
|
||||
- 命名返回值
|
||||
- 错误处理模式
|
||||
- 返回值解构
|
||||
- 忽略返回值
|
||||
- 多返回值的性能考虑
|
||||
- 实际应用场景
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言多返回值详解 ===\n")
|
||||
|
||||
// 演示基本多返回值
|
||||
demonstrateBasicMultipleReturns()
|
||||
|
||||
// 演示命名返回值
|
||||
demonstrateNamedReturns()
|
||||
|
||||
// 演示错误处理模式
|
||||
demonstrateErrorHandling()
|
||||
|
||||
// 演示返回值解构和忽略
|
||||
demonstrateReturnValueHandling()
|
||||
|
||||
// 演示多返回值的实际应用
|
||||
demonstratePracticalApplications()
|
||||
|
||||
// 演示多返回值的高级用法
|
||||
demonstrateAdvancedUsage()
|
||||
|
||||
// 演示性能考虑
|
||||
demonstratePerformanceConsiderations()
|
||||
}
|
||||
|
||||
// demonstrateBasicMultipleReturns 演示基本多返回值
|
||||
func demonstrateBasicMultipleReturns() {
|
||||
fmt.Println("1. 基本多返回值:")
|
||||
|
||||
// 两个返回值
|
||||
fmt.Printf(" 两个返回值:\n")
|
||||
quotient, remainder := divmod(17, 5)
|
||||
fmt.Printf(" 17 ÷ 5 = %d 余 %d\n", quotient, remainder)
|
||||
|
||||
// 三个返回值
|
||||
fmt.Printf(" 三个返回值:\n")
|
||||
min, max, avg := analyzeNumbers([]int{3, 7, 1, 9, 4, 6})
|
||||
fmt.Printf(" 数组 [3, 7, 1, 9, 4, 6] - 最小值: %d, 最大值: %d, 平均值: %.2f\n", min, max, avg)
|
||||
|
||||
// 不同类型的返回值
|
||||
fmt.Printf(" 不同类型的返回值:\n")
|
||||
name, age, height, isStudent := getPersonInfo()
|
||||
fmt.Printf(" 个人信息 - 姓名: %s, 年龄: %d, 身高: %.1fcm, 学生: %t\n",
|
||||
name, age, height, isStudent)
|
||||
|
||||
// 返回值和错误
|
||||
fmt.Printf(" 返回值和错误:\n")
|
||||
result, err := safeDivide(10, 2)
|
||||
if err != nil {
|
||||
fmt.Printf(" 错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 10 ÷ 2 = %.2f\n", result)
|
||||
}
|
||||
|
||||
result, err = safeDivide(10, 0)
|
||||
if err != nil {
|
||||
fmt.Printf(" 错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 10 ÷ 0 = %.2f\n", result)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateNamedReturns 演示命名返回值
|
||||
func demonstrateNamedReturns() {
|
||||
fmt.Println("2. 命名返回值:")
|
||||
|
||||
// 基本命名返回值
|
||||
fmt.Printf(" 基本命名返回值:\n")
|
||||
area, perimeter := calculateRectangle(5, 3)
|
||||
fmt.Printf(" 矩形 5×3 - 面积: %d, 周长: %d\n", area, perimeter)
|
||||
|
||||
// 命名返回值的提前返回
|
||||
fmt.Printf(" 命名返回值的提前返回:\n")
|
||||
score, grade, pass := evaluateScore(85)
|
||||
fmt.Printf(" 分数 85 - 等级: %s, 是否及格: %t\n", grade, pass)
|
||||
|
||||
score, grade, pass = evaluateScore(45)
|
||||
fmt.Printf(" 分数 45 - 等级: %s, 是否及格: %t\n", grade, pass)
|
||||
|
||||
// 复杂的命名返回值
|
||||
fmt.Printf(" 复杂的命名返回值:\n")
|
||||
valid, reason, suggestions := validatePassword("123")
|
||||
fmt.Printf(" 密码 \"123\" - 有效: %t, 原因: %s\n", valid, reason)
|
||||
if len(suggestions) > 0 {
|
||||
fmt.Printf(" 建议: %v\n", suggestions)
|
||||
}
|
||||
|
||||
valid, reason, suggestions = validatePassword("SecurePass123!")
|
||||
fmt.Printf(" 密码 \"SecurePass123!\" - 有效: %t, 原因: %s\n", valid, reason)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateErrorHandling 演示错误处理模式
|
||||
func demonstrateErrorHandling() {
|
||||
fmt.Println("3. 错误处理模式:")
|
||||
|
||||
// 标准错误处理模式
|
||||
fmt.Printf(" 标准错误处理模式:\n")
|
||||
|
||||
// 字符串转整数
|
||||
value, err := parseInteger("123")
|
||||
if err != nil {
|
||||
fmt.Printf(" 解析错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 解析成功: %d\n", value)
|
||||
}
|
||||
|
||||
value, err = parseInteger("abc")
|
||||
if err != nil {
|
||||
fmt.Printf(" 解析错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 解析成功: %d\n", value)
|
||||
}
|
||||
|
||||
// 文件操作模拟
|
||||
fmt.Printf(" 文件操作模拟:\n")
|
||||
content, err := readFile("config.txt")
|
||||
if err != nil {
|
||||
fmt.Printf(" 读取文件错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 文件内容: %s\n", content)
|
||||
}
|
||||
|
||||
// 网络请求模拟
|
||||
fmt.Printf(" 网络请求模拟:\n")
|
||||
data, statusCode, err := httpGet("https://api.example.com/users")
|
||||
if err != nil {
|
||||
fmt.Printf(" 请求错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 状态码: %d, 数据长度: %d\n", statusCode, len(data))
|
||||
}
|
||||
|
||||
// 多层错误处理
|
||||
fmt.Printf(" 多层错误处理:\n")
|
||||
result, err := processUserData("user123")
|
||||
if err != nil {
|
||||
fmt.Printf(" 处理用户数据错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 处理结果: %s\n", result)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateReturnValueHandling 演示返回值解构和忽略
|
||||
func demonstrateReturnValueHandling() {
|
||||
fmt.Println("4. 返回值解构和忽略:")
|
||||
|
||||
// 接收所有返回值
|
||||
fmt.Printf(" 接收所有返回值:\n")
|
||||
x, y, z := getCoordinates()
|
||||
fmt.Printf(" 坐标: (%d, %d, %d)\n", x, y, z)
|
||||
|
||||
// 忽略某些返回值
|
||||
fmt.Printf(" 忽略某些返回值:\n")
|
||||
_, _, avgZ := getCoordinates()
|
||||
fmt.Printf(" 只关心 Z 坐标: %d\n", avgZ)
|
||||
|
||||
// 只检查错误
|
||||
fmt.Printf(" 只检查错误:\n")
|
||||
_, err := safeDivide(10, 2)
|
||||
if err != nil {
|
||||
fmt.Printf(" 操作失败: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 操作成功\n")
|
||||
}
|
||||
|
||||
// 链式调用
|
||||
fmt.Printf(" 链式调用:\n")
|
||||
result, err := processChain("input")
|
||||
if err != nil {
|
||||
fmt.Printf(" 链式处理错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 链式处理结果: %s\n", result)
|
||||
}
|
||||
|
||||
// 多重赋值
|
||||
fmt.Printf(" 多重赋值:\n")
|
||||
a, b := 10, 20
|
||||
fmt.Printf(" 交换前: a=%d, b=%d\n", a, b)
|
||||
a, b = swap(a, b)
|
||||
fmt.Printf(" 交换后: a=%d, b=%d\n", a, b)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalApplications 演示多返回值的实际应用
|
||||
func demonstratePracticalApplications() {
|
||||
fmt.Println("5. 多返回值的实际应用:")
|
||||
|
||||
// 应用1: 数据库查询模拟
|
||||
fmt.Printf(" 应用1 - 数据库查询模拟:\n")
|
||||
user, found, err := findUserByID(123)
|
||||
if err != nil {
|
||||
fmt.Printf(" 查询错误: %v\n", err)
|
||||
} else if !found {
|
||||
fmt.Printf(" 用户不存在\n")
|
||||
} else {
|
||||
fmt.Printf(" 找到用户: %+v\n", user)
|
||||
}
|
||||
|
||||
// 应用2: 缓存操作
|
||||
fmt.Printf(" 应用2 - 缓存操作:\n")
|
||||
value, hit, err := getFromCache("user:123")
|
||||
if err != nil {
|
||||
fmt.Printf(" 缓存错误: %v\n", err)
|
||||
} else if hit {
|
||||
fmt.Printf(" 缓存命中: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf(" 缓存未命中\n")
|
||||
}
|
||||
|
||||
// 应用3: 配置解析
|
||||
fmt.Printf(" 应用3 - 配置解析:\n")
|
||||
config, warnings, err := parseConfig("app.conf")
|
||||
if err != nil {
|
||||
fmt.Printf(" 配置解析错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 配置加载成功: %+v\n", config)
|
||||
if len(warnings) > 0 {
|
||||
fmt.Printf(" 警告: %v\n", warnings)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用4: 数据验证
|
||||
fmt.Printf(" 应用4 - 数据验证:\n")
|
||||
userData := map[string]string{
|
||||
"name": "Alice",
|
||||
"email": "alice@example.com",
|
||||
"age": "25",
|
||||
}
|
||||
|
||||
valid, errors := validateUserData(userData)
|
||||
fmt.Printf(" 用户数据验证 - 有效: %t\n", valid)
|
||||
if len(errors) > 0 {
|
||||
fmt.Printf(" 验证错误: %v\n", errors)
|
||||
}
|
||||
|
||||
// 应用5: 统计分析
|
||||
fmt.Printf(" 应用5 - 统计分析:\n")
|
||||
data := []float64{1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0}
|
||||
mean, median, stddev := calculateStatistics(data)
|
||||
fmt.Printf(" 数据: %v\n", data)
|
||||
fmt.Printf(" 统计结果 - 平均值: %.2f, 中位数: %.2f, 标准差: %.2f\n",
|
||||
mean, median, stddev)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAdvancedUsage 演示多返回值的高级用法
|
||||
func demonstrateAdvancedUsage() {
|
||||
fmt.Println("6. 多返回值的高级用法:")
|
||||
|
||||
// 返回函数
|
||||
fmt.Printf(" 返回函数:\n")
|
||||
add, multiply := getMathOperations()
|
||||
fmt.Printf(" add(5, 3) = %d\n", add(5, 3))
|
||||
fmt.Printf(" multiply(5, 3) = %d\n", multiply(5, 3))
|
||||
|
||||
// 返回接口
|
||||
fmt.Printf(" 返回接口:\n")
|
||||
reader, writer := getIOOperations()
|
||||
data := []byte("Hello, World!")
|
||||
|
||||
n, err := writer.Write(data)
|
||||
if err != nil {
|
||||
fmt.Printf(" 写入错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 写入 %d 字节\n", n)
|
||||
}
|
||||
|
||||
buffer := make([]byte, 13)
|
||||
n, err = reader.Read(buffer)
|
||||
if err != nil {
|
||||
fmt.Printf(" 读取错误: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf(" 读取 %d 字节: %s\n", n, string(buffer[:n]))
|
||||
}
|
||||
|
||||
// 返回通道
|
||||
fmt.Printf(" 返回通道:\n")
|
||||
input, output := createPipeline()
|
||||
|
||||
// 发送数据
|
||||
go func() {
|
||||
for i := 1; i <= 3; i++ {
|
||||
input <- i
|
||||
}
|
||||
close(input)
|
||||
}()
|
||||
|
||||
// 接收处理后的数据
|
||||
for result := range output {
|
||||
fmt.Printf(" 处理结果: %d\n", result)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePerformanceConsiderations 演示性能考虑
|
||||
func demonstratePerformanceConsiderations() {
|
||||
fmt.Println("7. 性能考虑:")
|
||||
|
||||
// 返回值的内存分配
|
||||
fmt.Printf(" 返回值的内存分配:\n")
|
||||
|
||||
// 返回值拷贝 vs 返回指针
|
||||
largeData := make([]int, 1000)
|
||||
for i := range largeData {
|
||||
largeData[i] = i
|
||||
}
|
||||
|
||||
// 返回拷贝(可能影响性能)
|
||||
copied, size := copyLargeData(largeData)
|
||||
fmt.Printf(" 返回拷贝 - 大小: %d, 第一个元素: %d\n", size, copied[0])
|
||||
|
||||
// 返回指针(更高效)
|
||||
ptr, size := referenceLargeData(largeData)
|
||||
fmt.Printf(" 返回指针 - 大小: %d, 第一个元素: %d\n", size, (*ptr)[0])
|
||||
|
||||
// 多返回值 vs 结构体
|
||||
fmt.Printf(" 多返回值 vs 结构体:\n")
|
||||
|
||||
// 使用多返回值
|
||||
name, age, email := getUserInfo1()
|
||||
fmt.Printf(" 多返回值: %s, %d, %s\n", name, age, email)
|
||||
|
||||
// 使用结构体
|
||||
user := getUserInfo2()
|
||||
fmt.Printf(" 结构体: %s, %d, %s\n", user.Name, user.Age, user.Email)
|
||||
|
||||
// 错误处理的性能
|
||||
fmt.Printf(" 错误处理的性能:\n")
|
||||
|
||||
// 正常情况
|
||||
start := time.Now()
|
||||
for i := 0; i < 1000; i++ {
|
||||
_, err := fastOperation(i)
|
||||
if err != nil {
|
||||
// 处理错误
|
||||
}
|
||||
}
|
||||
duration := time.Since(start)
|
||||
fmt.Printf(" 1000次正常操作耗时: %v\n", duration)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// ========== 函数定义 ==========
|
||||
|
||||
// 基本多返回值函数
|
||||
func divmod(a, b int) (int, int) {
|
||||
return a / b, a % b
|
||||
}
|
||||
|
||||
func analyzeNumbers(numbers []int) (int, int, float64) {
|
||||
if len(numbers) == 0 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
min, max := numbers[0], numbers[0]
|
||||
sum := 0
|
||||
|
||||
for _, num := range numbers {
|
||||
if num < min {
|
||||
min = num
|
||||
}
|
||||
if num > max {
|
||||
max = num
|
||||
}
|
||||
sum += num
|
||||
}
|
||||
|
||||
avg := float64(sum) / float64(len(numbers))
|
||||
return min, max, avg
|
||||
}
|
||||
|
||||
func getPersonInfo() (string, int, float64, bool) {
|
||||
return "Alice", 25, 165.5, true
|
||||
}
|
||||
|
||||
func safeDivide(a, b float64) (float64, error) {
|
||||
if b == 0 {
|
||||
return 0, errors.New("除数不能为零")
|
||||
}
|
||||
return a / b, nil
|
||||
}
|
||||
|
||||
// 命名返回值函数
|
||||
func calculateRectangle(width, height int) (area, perimeter int) {
|
||||
area = width * height
|
||||
perimeter = 2 * (width + height)
|
||||
return // 自动返回命名的返回值
|
||||
}
|
||||
|
||||
func evaluateScore(score int) (originalScore int, grade string, pass bool) {
|
||||
originalScore = score
|
||||
|
||||
if score < 0 || score > 100 {
|
||||
grade = "无效"
|
||||
return // 提前返回
|
||||
}
|
||||
|
||||
switch {
|
||||
case score >= 90:
|
||||
grade = "A"
|
||||
case score >= 80:
|
||||
grade = "B"
|
||||
case score >= 70:
|
||||
grade = "C"
|
||||
case score >= 60:
|
||||
grade = "D"
|
||||
default:
|
||||
grade = "F"
|
||||
}
|
||||
|
||||
pass = score >= 60
|
||||
return
|
||||
}
|
||||
|
||||
func validatePassword(password string) (valid bool, reason string, suggestions []string) {
|
||||
if len(password) < 8 {
|
||||
reason = "密码长度不足8位"
|
||||
suggestions = append(suggestions, "增加密码长度")
|
||||
return
|
||||
}
|
||||
|
||||
hasUpper := strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
hasLower := strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz")
|
||||
hasDigit := strings.ContainsAny(password, "0123456789")
|
||||
hasSpecial := strings.ContainsAny(password, "!@#$%^&*")
|
||||
|
||||
if !hasUpper {
|
||||
suggestions = append(suggestions, "添加大写字母")
|
||||
}
|
||||
if !hasLower {
|
||||
suggestions = append(suggestions, "添加小写字母")
|
||||
}
|
||||
if !hasDigit {
|
||||
suggestions = append(suggestions, "添加数字")
|
||||
}
|
||||
if !hasSpecial {
|
||||
suggestions = append(suggestions, "添加特殊字符")
|
||||
}
|
||||
|
||||
if hasUpper && hasLower && hasDigit && hasSpecial {
|
||||
valid = true
|
||||
reason = "密码强度良好"
|
||||
} else {
|
||||
reason = "密码强度不足"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 错误处理函数
|
||||
func parseInteger(s string) (int, error) {
|
||||
value, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("无法解析整数 '%s': %w", s, err)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func readFile(filename string) (string, error) {
|
||||
// 模拟文件读取
|
||||
if filename == "config.txt" {
|
||||
return "server_port=8080\ndebug=true", nil
|
||||
}
|
||||
return "", fmt.Errorf("文件 '%s' 不存在", filename)
|
||||
}
|
||||
|
||||
func httpGet(url string) ([]byte, int, error) {
|
||||
// 模拟HTTP请求
|
||||
if strings.Contains(url, "example.com") {
|
||||
return []byte(`{"users": [{"id": 1, "name": "Alice"}]}`), 200, nil
|
||||
}
|
||||
return nil, 0, errors.New("网络连接失败")
|
||||
}
|
||||
|
||||
func processUserData(userID string) (string, error) {
|
||||
// 模拟多层处理
|
||||
if userID == "" {
|
||||
return "", errors.New("用户ID不能为空")
|
||||
}
|
||||
|
||||
// 模拟数据库查询
|
||||
if userID == "user123" {
|
||||
return "用户数据处理完成", nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("用户 '%s' 不存在", userID)
|
||||
}
|
||||
|
||||
// 返回值处理函数
|
||||
func getCoordinates() (int, int, int) {
|
||||
return 10, 20, 30
|
||||
}
|
||||
|
||||
func processChain(input string) (string, error) {
|
||||
if input == "" {
|
||||
return "", errors.New("输入不能为空")
|
||||
}
|
||||
|
||||
// 模拟处理链
|
||||
step1 := strings.ToUpper(input)
|
||||
step2 := step1 + "_PROCESSED"
|
||||
|
||||
return step2, nil
|
||||
}
|
||||
|
||||
func swap(a, b int) (int, int) {
|
||||
return b, a
|
||||
}
|
||||
|
||||
// 实际应用函数
|
||||
type User struct {
|
||||
ID int
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
func findUserByID(id int) (User, bool, error) {
|
||||
// 模拟数据库查询
|
||||
if id <= 0 {
|
||||
return User{}, false, errors.New("无效的用户ID")
|
||||
}
|
||||
|
||||
if id == 123 {
|
||||
return User{ID: 123, Name: "Alice", Email: "alice@example.com"}, true, nil
|
||||
}
|
||||
|
||||
return User{}, false, nil
|
||||
}
|
||||
|
||||
func getFromCache(key string) (string, bool, error) {
|
||||
// 模拟缓存操作
|
||||
cache := map[string]string{
|
||||
"user:123": "Alice",
|
||||
"user:456": "Bob",
|
||||
}
|
||||
|
||||
if value, exists := cache[key]; exists {
|
||||
return value, true, nil
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
Debug bool
|
||||
Timeout int
|
||||
}
|
||||
|
||||
func parseConfig(filename string) (Config, []string, error) {
|
||||
// 模拟配置解析
|
||||
config := Config{Port: 8080, Debug: true, Timeout: 30}
|
||||
warnings := []string{"使用默认超时值"}
|
||||
|
||||
if filename == "app.conf" {
|
||||
return config, warnings, nil
|
||||
}
|
||||
|
||||
return Config{}, nil, fmt.Errorf("配置文件 '%s' 不存在", filename)
|
||||
}
|
||||
|
||||
func validateUserData(data map[string]string) (bool, []string) {
|
||||
var errors []string
|
||||
|
||||
if name := data["name"]; name == "" {
|
||||
errors = append(errors, "姓名不能为空")
|
||||
}
|
||||
|
||||
if email := data["email"]; !strings.Contains(email, "@") {
|
||||
errors = append(errors, "邮箱格式无效")
|
||||
}
|
||||
|
||||
if ageStr := data["age"]; ageStr != "" {
|
||||
if age, err := strconv.Atoi(ageStr); err != nil || age < 0 || age > 150 {
|
||||
errors = append(errors, "年龄无效")
|
||||
}
|
||||
}
|
||||
|
||||
return len(errors) == 0, errors
|
||||
}
|
||||
|
||||
func calculateStatistics(data []float64) (mean, median, stddev float64) {
|
||||
if len(data) == 0 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
// 计算平均值
|
||||
sum := 0.0
|
||||
for _, v := range data {
|
||||
sum += v
|
||||
}
|
||||
mean = sum / float64(len(data))
|
||||
|
||||
// 计算中位数(简化版)
|
||||
median = data[len(data)/2]
|
||||
|
||||
// 计算标准差
|
||||
variance := 0.0
|
||||
for _, v := range data {
|
||||
variance += (v - mean) * (v - mean)
|
||||
}
|
||||
stddev = math.Sqrt(variance / float64(len(data)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 高级用法函数
|
||||
func getMathOperations() (func(int, int) int, func(int, int) int) {
|
||||
add := func(a, b int) int { return a + b }
|
||||
multiply := func(a, b int) int { return a * b }
|
||||
return add, multiply
|
||||
}
|
||||
|
||||
type MockReader struct {
|
||||
data []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func (r *MockReader) Read(p []byte) (n int, error) {
|
||||
if r.pos >= len(r.data) {
|
||||
return 0, errors.New("EOF")
|
||||
}
|
||||
|
||||
n = copy(p, r.data[r.pos:])
|
||||
r.pos += n
|
||||
return n, nil
|
||||
}
|
||||
|
||||
type MockWriter struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (w *MockWriter) Write(p []byte) (n int, error) {
|
||||
w.data = append(w.data, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func getIOOperations() (*MockReader, *MockWriter) {
|
||||
reader := &MockReader{data: []byte("Hello, World!")}
|
||||
writer := &MockWriter{}
|
||||
return reader, writer
|
||||
}
|
||||
|
||||
func createPipeline() (chan<- int, <-chan int) {
|
||||
input := make(chan int)
|
||||
output := make(chan int)
|
||||
|
||||
go func() {
|
||||
defer close(output)
|
||||
for value := range input {
|
||||
output <- value * 2 // 处理数据
|
||||
}
|
||||
}()
|
||||
|
||||
return input, output
|
||||
}
|
||||
|
||||
// 性能考虑函数
|
||||
func copyLargeData(data []int) ([]int, int) {
|
||||
copied := make([]int, len(data))
|
||||
copy(copied, data)
|
||||
return copied, len(copied)
|
||||
}
|
||||
|
||||
func referenceLargeData(data []int) (*[]int, int) {
|
||||
return &data, len(data)
|
||||
}
|
||||
|
||||
func getUserInfo1() (string, int, string) {
|
||||
return "Alice", 25, "alice@example.com"
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
Name string
|
||||
Age int
|
||||
Email string
|
||||
}
|
||||
|
||||
func getUserInfo2() UserInfo {
|
||||
return UserInfo{Name: "Alice", Age: 25, Email: "alice@example.com"}
|
||||
}
|
||||
|
||||
func fastOperation(n int) (int, error) {
|
||||
if n < 0 {
|
||||
return 0, errors.New("负数")
|
||||
}
|
||||
return n * 2, nil
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 02-multiple-returns.go
|
||||
|
||||
学习要点:
|
||||
1. Go 支持多返回值,这是其独特且强大的特性
|
||||
2. 多返回值常用于返回结果和错误信息
|
||||
3. 命名返回值可以提高代码可读性,支持提前返回
|
||||
4. 可以使用 _ 忽略不需要的返回值
|
||||
5. 多返回值是 Go 错误处理的基础
|
||||
|
||||
多返回值的优势:
|
||||
1. 避免使用指针参数传递多个结果
|
||||
2. 使错误处理更加明确和一致
|
||||
3. 提高代码的可读性和维护性
|
||||
4. 支持函数式编程风格
|
||||
|
||||
常见模式:
|
||||
1. (result, error) - 标准错误处理模式
|
||||
2. (value, ok) - 检查操作是否成功
|
||||
3. (value, found, error) - 查询操作模式
|
||||
4. 命名返回值 - 提高可读性
|
||||
|
||||
最佳实践:
|
||||
1. 错误通常作为最后一个返回值
|
||||
2. 使用命名返回值提高复杂函数的可读性
|
||||
3. 适当使用 _ 忽略不需要的返回值
|
||||
4. 保持返回值数量合理(通常不超过3-4个)
|
||||
5. 考虑使用结构体替代过多的返回值
|
||||
|
||||
性能考虑:
|
||||
1. 多返回值通常比传递指针参数更高效
|
||||
2. 大对象考虑返回指针而不是值拷贝
|
||||
3. 命名返回值可能有轻微的性能开销
|
||||
4. 错误处理的性能影响通常可以忽略
|
||||
|
||||
应用场景:
|
||||
1. 错误处理
|
||||
2. 数据库查询
|
||||
3. 网络操作
|
||||
4. 文件操作
|
||||
5. 数据验证
|
||||
6. 统计计算
|
||||
7. 缓存操作
|
||||
*/
|
757
golang-learning/03-functions/03-variadic-functions.go
Normal file
757
golang-learning/03-functions/03-variadic-functions.go
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
03-variadic-functions.go - Go 语言可变参数函数详解
|
||||
|
||||
学习目标:
|
||||
1. 掌握可变参数函数的语法
|
||||
2. 理解可变参数的传递机制
|
||||
3. 学会可变参数的实际应用
|
||||
4. 了解可变参数的限制和注意事项
|
||||
5. 掌握可变参数的最佳实践
|
||||
|
||||
知识点:
|
||||
- 可变参数语法 (...type)
|
||||
- 可变参数的传递和展开
|
||||
- 空参数和单参数处理
|
||||
- 可变参数与切片的关系
|
||||
- 可变参数的类型限制
|
||||
- 实际应用场景
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言可变参数函数详解 ===\n")
|
||||
|
||||
// 演示基本可变参数函数
|
||||
demonstrateBasicVariadicFunctions()
|
||||
|
||||
// 演示可变参数的传递
|
||||
demonstrateVariadicParameterPassing()
|
||||
|
||||
// 演示可变参数与其他参数的组合
|
||||
demonstrateVariadicWithOtherParams()
|
||||
|
||||
// 演示可变参数的类型处理
|
||||
demonstrateVariadicTypeHandling()
|
||||
|
||||
// 演示可变参数的实际应用
|
||||
demonstratePracticalApplications()
|
||||
|
||||
// 演示可变参数的高级用法
|
||||
demonstrateAdvancedVariadicUsage()
|
||||
|
||||
// 演示可变参数的限制和注意事项
|
||||
demonstrateVariadicLimitations()
|
||||
}
|
||||
|
||||
// demonstrateBasicVariadicFunctions 演示基本可变参数函数
|
||||
func demonstrateBasicVariadicFunctions() {
|
||||
fmt.Println("1. 基本可变参数函数:")
|
||||
|
||||
// 数字求和
|
||||
fmt.Printf(" 数字求和:\n")
|
||||
fmt.Printf(" sum() = %d\n", sum())
|
||||
fmt.Printf(" sum(1) = %d\n", sum(1))
|
||||
fmt.Printf(" sum(1, 2, 3) = %d\n", sum(1, 2, 3))
|
||||
fmt.Printf(" sum(1, 2, 3, 4, 5) = %d\n", sum(1, 2, 3, 4, 5))
|
||||
|
||||
// 字符串连接
|
||||
fmt.Printf(" 字符串连接:\n")
|
||||
fmt.Printf(" concat() = \"%s\"\n", concat())
|
||||
fmt.Printf(" concat(\"Hello\") = \"%s\"\n", concat("Hello"))
|
||||
fmt.Printf(" concat(\"Hello\", \" \", \"World\") = \"%s\"\n",
|
||||
concat("Hello", " ", "World"))
|
||||
fmt.Printf(" concat(\"Go\", \" is\", \" awesome\", \"!\") = \"%s\"\n",
|
||||
concat("Go", " is", " awesome", "!"))
|
||||
|
||||
// 找最大值
|
||||
fmt.Printf(" 找最大值:\n")
|
||||
fmt.Printf(" max(1) = %d\n", max(1))
|
||||
fmt.Printf(" max(3, 1, 4, 1, 5) = %d\n", max(3, 1, 4, 1, 5))
|
||||
fmt.Printf(" max(10, 5, 8, 3, 9, 2, 7) = %d\n", max(10, 5, 8, 3, 9, 2, 7))
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateVariadicParameterPassing 演示可变参数的传递
|
||||
func demonstrateVariadicParameterPassing() {
|
||||
fmt.Println("2. 可变参数的传递:")
|
||||
|
||||
// 直接传递多个参数
|
||||
fmt.Printf(" 直接传递多个参数:\n")
|
||||
result1 := multiply(2, 3, 4, 5)
|
||||
fmt.Printf(" multiply(2, 3, 4, 5) = %d\n", result1)
|
||||
|
||||
// 传递切片(需要展开)
|
||||
fmt.Printf(" 传递切片(使用 ... 展开):\n")
|
||||
numbers := []int{2, 3, 4, 5}
|
||||
result2 := multiply(numbers...)
|
||||
fmt.Printf(" numbers := %v\n", numbers)
|
||||
fmt.Printf(" multiply(numbers...) = %d\n", result2)
|
||||
|
||||
// 混合传递
|
||||
fmt.Printf(" 混合传递:\n")
|
||||
result3 := multiply(1, 2)
|
||||
moreNumbers := []int{3, 4, 5}
|
||||
result4 := multiply(append([]int{1, 2}, moreNumbers...)...)
|
||||
fmt.Printf(" multiply(1, 2) = %d\n", result3)
|
||||
fmt.Printf(" 混合传递结果 = %d\n", result4)
|
||||
|
||||
// 空切片传递
|
||||
fmt.Printf(" 空切片传递:\n")
|
||||
var emptySlice []int
|
||||
result5 := multiply(emptySlice...)
|
||||
fmt.Printf(" multiply(emptySlice...) = %d\n", result5)
|
||||
|
||||
// 传递给其他可变参数函数
|
||||
fmt.Printf(" 传递给其他可变参数函数:\n")
|
||||
numbers2 := []int{10, 20, 30}
|
||||
avg := average(numbers2...)
|
||||
fmt.Printf(" average(%v) = %.2f\n", numbers2, avg)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateVariadicWithOtherParams 演示可变参数与其他参数的组合
|
||||
func demonstrateVariadicWithOtherParams() {
|
||||
fmt.Println("3. 可变参数与其他参数的组合:")
|
||||
|
||||
// 固定参数 + 可变参数
|
||||
fmt.Printf(" 固定参数 + 可变参数:\n")
|
||||
result1 := formatMessage("INFO", "User login", "successful", "from IP 192.168.1.1")
|
||||
fmt.Printf(" %s\n", result1)
|
||||
|
||||
result2 := formatMessage("ERROR", "Database connection failed")
|
||||
fmt.Printf(" %s\n", result2)
|
||||
|
||||
// 多个固定参数 + 可变参数
|
||||
fmt.Printf(" 多个固定参数 + 可变参数:\n")
|
||||
result3 := calculateWithOperation("add", 1, 2, 3, 4, 5)
|
||||
fmt.Printf(" calculateWithOperation(\"add\", 1, 2, 3, 4, 5) = %.2f\n", result3)
|
||||
|
||||
result4 := calculateWithOperation("multiply", 2, 3, 4)
|
||||
fmt.Printf(" calculateWithOperation(\"multiply\", 2, 3, 4) = %.2f\n", result4)
|
||||
|
||||
result5 := calculateWithOperation("average", 10, 20, 30, 40, 50)
|
||||
fmt.Printf(" calculateWithOperation(\"average\", 10, 20, 30, 40, 50) = %.2f\n", result5)
|
||||
|
||||
// 带默认值的可变参数函数
|
||||
fmt.Printf(" 带默认值的可变参数函数:\n")
|
||||
config1 := createConfig("myapp")
|
||||
fmt.Printf(" createConfig(\"myapp\") = %+v\n", config1)
|
||||
|
||||
config2 := createConfig("myapp", "debug=true", "port=8080", "timeout=30")
|
||||
fmt.Printf(" createConfig with options = %+v\n", config2)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateVariadicTypeHandling 演示可变参数的类型处理
|
||||
func demonstrateVariadicTypeHandling() {
|
||||
fmt.Println("4. 可变参数的类型处理:")
|
||||
|
||||
// 不同类型的可变参数
|
||||
fmt.Printf(" 字符串可变参数:\n")
|
||||
joined := joinStrings(", ", "apple", "banana", "cherry", "date")
|
||||
fmt.Printf(" joinStrings(\", \", \"apple\", \"banana\", \"cherry\", \"date\") = \"%s\"\n", joined)
|
||||
|
||||
// 接口类型的可变参数
|
||||
fmt.Printf(" 接口类型的可变参数:\n")
|
||||
printValues("混合类型:", 42, "hello", 3.14, true, []int{1, 2, 3})
|
||||
|
||||
// 结构体类型的可变参数
|
||||
fmt.Printf(" 结构体类型的可变参数:\n")
|
||||
person1 := Person{Name: "Alice", Age: 25}
|
||||
person2 := Person{Name: "Bob", Age: 30}
|
||||
person3 := Person{Name: "Charlie", Age: 35}
|
||||
|
||||
avgAge := calculateAverageAge(person1, person2, person3)
|
||||
fmt.Printf(" 平均年龄: %.1f\n", avgAge)
|
||||
|
||||
// 函数类型的可变参数
|
||||
fmt.Printf(" 函数类型的可变参数:\n")
|
||||
add := func(a, b int) int { return a + b }
|
||||
multiply := func(a, b int) int { return a * b }
|
||||
subtract := func(a, b int) int { return a - b }
|
||||
|
||||
results := applyOperations(10, 5, add, multiply, subtract)
|
||||
fmt.Printf(" applyOperations(10, 5, add, multiply, subtract) = %v\n", results)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstratePracticalApplications 演示可变参数的实际应用
|
||||
func demonstratePracticalApplications() {
|
||||
fmt.Println("5. 可变参数的实际应用:")
|
||||
|
||||
// 应用1: 日志记录
|
||||
fmt.Printf(" 应用1 - 日志记录:\n")
|
||||
logInfo("用户登录", "用户ID", 123, "IP地址", "192.168.1.1")
|
||||
logError("数据库连接失败", "错误码", 1001, "重试次数", 3)
|
||||
logDebug("缓存命中", "键", "user:123", "值", "Alice")
|
||||
|
||||
// 应用2: SQL 查询构建
|
||||
fmt.Printf(" 应用2 - SQL 查询构建:\n")
|
||||
query1 := buildSelectQuery("users", "name", "email", "age")
|
||||
fmt.Printf(" %s\n", query1)
|
||||
|
||||
query2 := buildSelectQuery("products", "id", "name", "price", "category", "stock")
|
||||
fmt.Printf(" %s\n", query2)
|
||||
|
||||
// 应用3: HTTP 路由注册
|
||||
fmt.Printf(" 应用3 - HTTP 路由注册:\n")
|
||||
registerRoute("GET", "/users", authMiddleware, loggingMiddleware, getUsersHandler)
|
||||
registerRoute("POST", "/users", authMiddleware, validateMiddleware, createUserHandler)
|
||||
|
||||
// 应用4: 数据验证
|
||||
fmt.Printf(" 应用4 - 数据验证:\n")
|
||||
userData := map[string]interface{}{
|
||||
"name": "Alice",
|
||||
"email": "alice@example.com",
|
||||
"age": 25,
|
||||
}
|
||||
|
||||
errors := validateData(userData,
|
||||
validateRequired("name"),
|
||||
validateEmail("email"),
|
||||
validateRange("age", 0, 150),
|
||||
)
|
||||
|
||||
if len(errors) == 0 {
|
||||
fmt.Printf(" 数据验证通过\n")
|
||||
} else {
|
||||
fmt.Printf(" 验证错误: %v\n", errors)
|
||||
}
|
||||
|
||||
// 应用5: 配置合并
|
||||
fmt.Printf(" 应用5 - 配置合并:\n")
|
||||
defaultConfig := Config{Port: 8080, Debug: false, Timeout: 30}
|
||||
userConfig := Config{Debug: true, MaxConnections: 100}
|
||||
envConfig := Config{Port: 9090, Timeout: 60}
|
||||
|
||||
finalConfig := mergeConfigs(defaultConfig, userConfig, envConfig)
|
||||
fmt.Printf(" 最终配置: %+v\n", finalConfig)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAdvancedVariadicUsage 演示可变参数的高级用法
|
||||
func demonstrateAdvancedVariadicUsage() {
|
||||
fmt.Println("6. 可变参数的高级用法:")
|
||||
|
||||
// 可变参数的递归处理
|
||||
fmt.Printf(" 可变参数的递归处理:\n")
|
||||
result1 := recursiveSum(1, 2, 3, 4, 5)
|
||||
fmt.Printf(" recursiveSum(1, 2, 3, 4, 5) = %d\n", result1)
|
||||
|
||||
// 可变参数的函数式处理
|
||||
fmt.Printf(" 可变参数的函数式处理:\n")
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
evenSum := reduceInts(filterInts(numbers, isEven)...)
|
||||
fmt.Printf(" 偶数之和: %d\n", evenSum)
|
||||
|
||||
oddProduct := reduceInts(filterInts(numbers, isOdd)...)
|
||||
fmt.Printf(" 奇数之和: %d\n", oddProduct)
|
||||
|
||||
// 可变参数的管道处理
|
||||
fmt.Printf(" 可变参数的管道处理:\n")
|
||||
pipeline := createPipeline(
|
||||
func(x int) int { return x * 2 }, // 乘以2
|
||||
func(x int) int { return x + 1 }, // 加1
|
||||
func(x int) int { return x * x }, // 平方
|
||||
)
|
||||
|
||||
for i := 1; i <= 3; i++ {
|
||||
result := pipeline(i)
|
||||
fmt.Printf(" pipeline(%d) = %d\n", i, result)
|
||||
}
|
||||
|
||||
// 可变参数的选项模式
|
||||
fmt.Printf(" 可变参数的选项模式:\n")
|
||||
server1 := createServer("localhost",
|
||||
withPort(8080),
|
||||
withTimeout(30),
|
||||
withDebug(true),
|
||||
)
|
||||
fmt.Printf(" 服务器1: %+v\n", server1)
|
||||
|
||||
server2 := createServer("0.0.0.0",
|
||||
withPort(9090),
|
||||
withMaxConnections(1000),
|
||||
)
|
||||
fmt.Printf(" 服务器2: %+v\n", server2)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateVariadicLimitations 演示可变参数的限制和注意事项
|
||||
func demonstrateVariadicLimitations() {
|
||||
fmt.Println("7. 可变参数的限制和注意事项:")
|
||||
|
||||
// 限制1: 可变参数必须是最后一个参数
|
||||
fmt.Printf(" 限制1: 可变参数必须是最后一个参数\n")
|
||||
fmt.Printf(" ✓ func example(a int, b ...string) - 正确\n")
|
||||
fmt.Printf(" ✗ func example(a ...int, b string) - 错误\n")
|
||||
|
||||
// 限制2: 一个函数只能有一个可变参数
|
||||
fmt.Printf(" 限制2: 一个函数只能有一个可变参数\n")
|
||||
fmt.Printf(" ✗ func example(a ...int, b ...string) - 错误\n")
|
||||
|
||||
// 注意事项1: 可变参数是切片
|
||||
fmt.Printf(" 注意事项1: 可变参数在函数内部是切片\n")
|
||||
inspectVariadicParam(1, 2, 3, 4, 5)
|
||||
|
||||
// 注意事项2: 修改可变参数会影响原始切片
|
||||
fmt.Printf(" 注意事项2: 修改可变参数可能影响原始数据\n")
|
||||
originalSlice := []int{1, 2, 3, 4, 5}
|
||||
fmt.Printf(" 修改前: %v\n", originalSlice)
|
||||
modifyVariadicParam(originalSlice...)
|
||||
fmt.Printf(" 修改后: %v\n", originalSlice)
|
||||
|
||||
// 注意事项3: 性能考虑
|
||||
fmt.Printf(" 注意事项3: 性能考虑\n")
|
||||
fmt.Printf(" - 传递大量参数时,切片展开可能有性能开销\n")
|
||||
fmt.Printf(" - 考虑直接传递切片而不是可变参数\n")
|
||||
|
||||
// 注意事项4: 类型安全
|
||||
fmt.Printf(" 注意事项4: 类型安全\n")
|
||||
fmt.Printf(" - 可变参数必须是相同类型\n")
|
||||
fmt.Printf(" - 使用 interface{} 可以接受不同类型,但失去类型安全\n")
|
||||
|
||||
// 最佳实践
|
||||
fmt.Printf(" 最佳实践:\n")
|
||||
fmt.Printf(" 1. 优先考虑切片参数而不是可变参数\n")
|
||||
fmt.Printf(" 2. 可变参数适用于调用时参数数量不确定的场景\n")
|
||||
fmt.Printf(" 3. 注意可变参数的性能影响\n")
|
||||
fmt.Printf(" 4. 使用选项模式处理复杂的可选参数\n")
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// ========== 函数定义 ==========
|
||||
|
||||
// 基本可变参数函数
|
||||
func sum(numbers ...int) int {
|
||||
total := 0
|
||||
for _, num := range numbers {
|
||||
total += num
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func concat(strings ...string) string {
|
||||
result := ""
|
||||
for _, str := range strings {
|
||||
result += str
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func max(numbers ...int) int {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
maximum := numbers[0]
|
||||
for _, num := range numbers {
|
||||
if num > maximum {
|
||||
maximum = num
|
||||
}
|
||||
}
|
||||
return maximum
|
||||
}
|
||||
|
||||
func multiply(numbers ...int) int {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
result := 1
|
||||
for _, num := range numbers {
|
||||
result *= num
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func average(numbers ...int) float64 {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
total := sum(numbers...)
|
||||
return float64(total) / float64(len(numbers))
|
||||
}
|
||||
|
||||
// 固定参数 + 可变参数
|
||||
func formatMessage(level string, messages ...string) string {
|
||||
timestamp := "2024-01-01 12:00:00"
|
||||
allMessages := strings.Join(messages, " ")
|
||||
return fmt.Sprintf("[%s] %s: %s", timestamp, level, allMessages)
|
||||
}
|
||||
|
||||
func calculateWithOperation(operation string, numbers ...int) float64 {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch operation {
|
||||
case "add":
|
||||
return float64(sum(numbers...))
|
||||
case "multiply":
|
||||
return float64(multiply(numbers...))
|
||||
case "average":
|
||||
return average(numbers...)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
Name string
|
||||
Options map[string]string
|
||||
}
|
||||
|
||||
func createConfig(name string, options ...string) AppConfig {
|
||||
config := AppConfig{
|
||||
Name: name,
|
||||
Options: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
parts := strings.SplitN(option, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
config.Options[parts[0]] = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// 类型处理函数
|
||||
func joinStrings(separator string, strings ...string) string {
|
||||
return strings.Join(strings, separator)
|
||||
}
|
||||
|
||||
func printValues(prefix string, values ...interface{}) {
|
||||
fmt.Printf(" %s ", prefix)
|
||||
for i, value := range values {
|
||||
if i > 0 {
|
||||
fmt.Printf(", ")
|
||||
}
|
||||
fmt.Printf("%v", value)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func calculateAverageAge(people ...Person) float64 {
|
||||
if len(people) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
totalAge := 0
|
||||
for _, person := range people {
|
||||
totalAge += person.Age
|
||||
}
|
||||
|
||||
return float64(totalAge) / float64(len(people))
|
||||
}
|
||||
|
||||
func applyOperations(a, b int, operations ...func(int, int) int) []int {
|
||||
results := make([]int, len(operations))
|
||||
for i, op := range operations {
|
||||
results[i] = op(a, b)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// 实际应用函数
|
||||
func logInfo(message string, keyValues ...interface{}) {
|
||||
fmt.Printf(" [INFO] %s", message)
|
||||
for i := 0; i < len(keyValues); i += 2 {
|
||||
if i+1 < len(keyValues) {
|
||||
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
func logError(message string, keyValues ...interface{}) {
|
||||
fmt.Printf(" [ERROR] %s", message)
|
||||
for i := 0; i < len(keyValues); i += 2 {
|
||||
if i+1 < len(keyValues) {
|
||||
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
func logDebug(message string, keyValues ...interface{}) {
|
||||
fmt.Printf(" [DEBUG] %s", message)
|
||||
for i := 0; i < len(keyValues); i += 2 {
|
||||
if i+1 < len(keyValues) {
|
||||
fmt.Printf(" %v=%v", keyValues[i], keyValues[i+1])
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
func buildSelectQuery(table string, columns ...string) string {
|
||||
if len(columns) == 0 {
|
||||
return fmt.Sprintf("SELECT * FROM %s", table)
|
||||
}
|
||||
return fmt.Sprintf("SELECT %s FROM %s", strings.Join(columns, ", "), table)
|
||||
}
|
||||
|
||||
// 模拟中间件和处理器
|
||||
func authMiddleware() { fmt.Printf(" - 认证中间件\n") }
|
||||
func loggingMiddleware() { fmt.Printf(" - 日志中间件\n") }
|
||||
func validateMiddleware() { fmt.Printf(" - 验证中间件\n") }
|
||||
func getUsersHandler() { fmt.Printf(" - 获取用户处理器\n") }
|
||||
func createUserHandler() { fmt.Printf(" - 创建用户处理器\n") }
|
||||
|
||||
func registerRoute(method, path string, handlers ...func()) {
|
||||
fmt.Printf(" 注册路由: %s %s\n", method, path)
|
||||
for _, handler := range handlers {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
// 验证函数类型
|
||||
type ValidationFunc func(map[string]interface{}) []string
|
||||
|
||||
func validateRequired(field string) ValidationFunc {
|
||||
return func(data map[string]interface{}) []string {
|
||||
if _, exists := data[field]; !exists {
|
||||
return []string{fmt.Sprintf("字段 %s 是必需的", field)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateEmail(field string) ValidationFunc {
|
||||
return func(data map[string]interface{}) []string {
|
||||
if email, ok := data[field].(string); ok {
|
||||
if !strings.Contains(email, "@") {
|
||||
return []string{fmt.Sprintf("字段 %s 不是有效的邮箱", field)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateRange(field string, min, max int) ValidationFunc {
|
||||
return func(data map[string]interface{}) []string {
|
||||
if value, ok := data[field].(int); ok {
|
||||
if value < min || value > max {
|
||||
return []string{fmt.Sprintf("字段 %s 必须在 %d-%d 范围内", field, min, max)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateData(data map[string]interface{}, validators ...ValidationFunc) []string {
|
||||
var allErrors []string
|
||||
for _, validator := range validators {
|
||||
if errors := validator(data); errors != nil {
|
||||
allErrors = append(allErrors, errors...)
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// 配置合并
|
||||
type Config struct {
|
||||
Port int
|
||||
Debug bool
|
||||
Timeout int
|
||||
MaxConnections int
|
||||
}
|
||||
|
||||
func mergeConfigs(configs ...Config) Config {
|
||||
result := Config{}
|
||||
|
||||
for _, config := range configs {
|
||||
if config.Port != 0 {
|
||||
result.Port = config.Port
|
||||
}
|
||||
if config.Debug {
|
||||
result.Debug = config.Debug
|
||||
}
|
||||
if config.Timeout != 0 {
|
||||
result.Timeout = config.Timeout
|
||||
}
|
||||
if config.MaxConnections != 0 {
|
||||
result.MaxConnections = config.MaxConnections
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 高级用法函数
|
||||
func recursiveSum(numbers ...int) int {
|
||||
if len(numbers) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(numbers) == 1 {
|
||||
return numbers[0]
|
||||
}
|
||||
return numbers[0] + recursiveSum(numbers[1:]...)
|
||||
}
|
||||
|
||||
func filterInts(numbers []int, predicate func(int) bool) []int {
|
||||
var result []int
|
||||
for _, num := range numbers {
|
||||
if predicate(num) {
|
||||
result = append(result, num)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func reduceInts(numbers ...int) int {
|
||||
return sum(numbers...)
|
||||
}
|
||||
|
||||
func isEven(n int) bool { return n%2 == 0 }
|
||||
func isOdd(n int) bool { return n%2 == 1 }
|
||||
|
||||
func createPipeline(functions ...func(int) int) func(int) int {
|
||||
return func(input int) int {
|
||||
result := input
|
||||
for _, fn := range functions {
|
||||
result = fn(result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// 选项模式
|
||||
type Server struct {
|
||||
Host string
|
||||
Port int
|
||||
Timeout int
|
||||
Debug bool
|
||||
MaxConnections int
|
||||
}
|
||||
|
||||
type ServerOption func(*Server)
|
||||
|
||||
func withPort(port int) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.Port = port
|
||||
}
|
||||
}
|
||||
|
||||
func withTimeout(timeout int) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.Timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
func withDebug(debug bool) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.Debug = debug
|
||||
}
|
||||
}
|
||||
|
||||
func withMaxConnections(max int) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.MaxConnections = max
|
||||
}
|
||||
}
|
||||
|
||||
func createServer(host string, options ...ServerOption) Server {
|
||||
server := Server{
|
||||
Host: host,
|
||||
Port: 80,
|
||||
Timeout: 10,
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(&server)
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// 限制和注意事项函数
|
||||
func inspectVariadicParam(numbers ...int) {
|
||||
fmt.Printf(" 可变参数类型: %T\n", numbers)
|
||||
fmt.Printf(" 可变参数长度: %d\n", len(numbers))
|
||||
fmt.Printf(" 可变参数容量: %d\n", cap(numbers))
|
||||
fmt.Printf(" 可变参数值: %v\n", numbers)
|
||||
}
|
||||
|
||||
func modifyVariadicParam(numbers ...int) {
|
||||
if len(numbers) > 0 {
|
||||
numbers[0] = 999 // 修改第一个元素
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 03-variadic-functions.go
|
||||
|
||||
学习要点:
|
||||
1. 可变参数使用 ...type 语法,必须是函数的最后一个参数
|
||||
2. 可变参数在函数内部是切片类型
|
||||
3. 传递切片给可变参数函数需要使用 ... 展开操作符
|
||||
4. 一个函数只能有一个可变参数
|
||||
5. 可变参数提供了灵活的函数调用方式
|
||||
|
||||
可变参数的语法:
|
||||
- 定义: func name(params ...type) { ... }
|
||||
- 调用: name(arg1, arg2, arg3) 或 name(slice...)
|
||||
- 内部: params 是 []type 类型的切片
|
||||
|
||||
常见应用场景:
|
||||
1. 数学运算函数(求和、求积等)
|
||||
2. 字符串处理函数
|
||||
3. 日志记录函数
|
||||
4. 配置和选项处理
|
||||
5. 中间件和处理器链
|
||||
6. 数据验证
|
||||
7. SQL 查询构建
|
||||
|
||||
最佳实践:
|
||||
1. 优先考虑切片参数,可变参数适用于调用便利性
|
||||
2. 使用选项模式处理复杂的可选参数
|
||||
3. 注意可变参数的性能影响
|
||||
4. 保持函数签名的简洁性
|
||||
5. 合理使用接口类型的可变参数
|
||||
|
||||
限制和注意事项:
|
||||
1. 可变参数必须是最后一个参数
|
||||
2. 一个函数只能有一个可变参数
|
||||
3. 可变参数是切片,修改会影响原始数据
|
||||
4. 大量参数时考虑性能影响
|
||||
5. 类型必须相同(除非使用 interface{})
|
||||
|
||||
高级用法:
|
||||
1. 函数式编程风格
|
||||
2. 选项模式
|
||||
3. 中间件模式
|
||||
4. 管道处理
|
||||
5. 递归处理
|
||||
6. 配置合并
|
||||
|
||||
性能考虑:
|
||||
1. 切片展开有一定开销
|
||||
2. 大量参数时考虑直接传递切片
|
||||
3. 避免在热点代码中过度使用
|
||||
4. 考虑内存分配的影响
|
||||
*/
|
1006
golang-learning/03-functions/04-closures.go
Normal file
1006
golang-learning/03-functions/04-closures.go
Normal file
File diff suppressed because it is too large
Load Diff
869
golang-learning/03-functions/05-methods.go
Normal file
869
golang-learning/03-functions/05-methods.go
Normal file
@@ -0,0 +1,869 @@
|
||||
/*
|
||||
05-methods.go - Go 语言方法详解
|
||||
|
||||
学习目标:
|
||||
1. 理解方法与函数的区别
|
||||
2. 掌握方法的定义和调用
|
||||
3. 学会值接收者和指针接收者的使用
|
||||
4. 了解方法集的概念
|
||||
5. 掌握方法的实际应用
|
||||
|
||||
知识点:
|
||||
- 方法定义语法
|
||||
- 值接收者 vs 指针接收者
|
||||
- 方法集和接口实现
|
||||
- 方法的继承和组合
|
||||
- 方法的实际应用场景
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== Go 语言方法详解 ===\n")
|
||||
|
||||
// 演示基本方法定义和调用
|
||||
demonstrateBasicMethods()
|
||||
|
||||
// 演示值接收者和指针接收者
|
||||
demonstrateReceiverTypes()
|
||||
|
||||
// 演示方法集和接口实现
|
||||
demonstrateMethodSets()
|
||||
|
||||
// 演示方法的继承和组合
|
||||
demonstrateMethodComposition()
|
||||
|
||||
// 演示方法的实际应用
|
||||
demonstratePracticalApplications()
|
||||
|
||||
// 演示方法的高级用法
|
||||
demonstrateAdvancedMethodUsage()
|
||||
}
|
||||
|
||||
// demonstrateBasicMethods 演示基本方法定义和调用
|
||||
func demonstrateBasicMethods() {
|
||||
fmt.Println("1. 基本方法定义和调用:")
|
||||
|
||||
// 创建结构体实例
|
||||
fmt.Printf(" 创建和使用基本方法:\n")
|
||||
|
||||
rect := Rectangle{Width: 10, Height: 5}
|
||||
fmt.Printf(" 矩形: %+v\n", rect)
|
||||
fmt.Printf(" 面积: %.2f\n", rect.Area())
|
||||
fmt.Printf(" 周长: %.2f\n", rect.Perimeter())
|
||||
|
||||
// 方法链调用
|
||||
fmt.Printf(" 方法链调用:\n")
|
||||
rect.SetWidth(8).SetHeight(6)
|
||||
fmt.Printf(" 修改后的矩形: %+v\n", rect)
|
||||
fmt.Printf(" 新面积: %.2f\n", rect.Area())
|
||||
|
||||
// 不同类型的方法
|
||||
fmt.Printf(" 不同类型的方法:\n")
|
||||
|
||||
circle := Circle{Radius: 3}
|
||||
fmt.Printf(" 圆形: %+v\n", circle)
|
||||
fmt.Printf(" 面积: %.2f\n", circle.Area())
|
||||
fmt.Printf(" 周长: %.2f\n", circle.Circumference())
|
||||
|
||||
// 基本类型的方法
|
||||
fmt.Printf(" 基本类型的方法:\n")
|
||||
|
||||
var temp Temperature = 25.5
|
||||
fmt.Printf(" 温度: %.1f°C\n", temp)
|
||||
fmt.Printf(" 华氏度: %.1f°F\n", temp.ToFahrenheit())
|
||||
fmt.Printf(" 开尔文: %.1f K\n", temp.ToKelvin())
|
||||
|
||||
fmt.Println()
|
||||
}// demonstr
|
||||
ateReceiverTypes 演示值接收者和指针接收者
|
||||
func demonstrateReceiverTypes() {
|
||||
fmt.Println("2. 值接收者和指针接收者:")
|
||||
|
||||
// 值接收者示例
|
||||
fmt.Printf(" 值接收者示例:\n")
|
||||
|
||||
counter1 := Counter{Value: 0}
|
||||
fmt.Printf(" 初始计数器: %+v\n", counter1)
|
||||
|
||||
// 值接收者方法不会修改原始值
|
||||
counter1.IncrementByValue()
|
||||
fmt.Printf(" 值接收者增加后: %+v\n", counter1) // 值不变
|
||||
|
||||
// 指针接收者示例
|
||||
fmt.Printf(" 指针接收者示例:\n")
|
||||
|
||||
counter2 := Counter{Value: 0}
|
||||
fmt.Printf(" 初始计数器: %+v\n", counter2)
|
||||
|
||||
// 指针接收者方法会修改原始值
|
||||
counter2.IncrementByPointer()
|
||||
fmt.Printf(" 指针接收者增加后: %+v\n", counter2) // 值改变
|
||||
|
||||
// 方法调用的自动转换
|
||||
fmt.Printf(" 方法调用的自动转换:\n")
|
||||
|
||||
counter3 := Counter{Value: 10}
|
||||
counterPtr := &counter3
|
||||
|
||||
// 值类型可以调用指针接收者方法(自动取地址)
|
||||
counter3.IncrementByPointer()
|
||||
fmt.Printf(" 值类型调用指针方法: %+v\n", counter3)
|
||||
|
||||
// 指针类型可以调用值接收者方法(自动解引用)
|
||||
result := counterPtr.GetValueCopy()
|
||||
fmt.Printf(" 指针类型调用值方法: %d\n", result)
|
||||
|
||||
// 大结构体的性能考虑
|
||||
fmt.Printf(" 大结构体的性能考虑:\n")
|
||||
|
||||
largeStruct := LargeStruct{}
|
||||
for i := 0; i < 1000; i++ {
|
||||
largeStruct.Data[i] = i
|
||||
}
|
||||
|
||||
// 值接收者会拷贝整个结构体
|
||||
start := time.Now()
|
||||
largeStruct.ProcessByValue()
|
||||
valueTime := time.Since(start)
|
||||
|
||||
// 指针接收者只传递指针
|
||||
start = time.Now()
|
||||
largeStruct.ProcessByPointer()
|
||||
pointerTime := time.Since(start)
|
||||
|
||||
fmt.Printf(" 值接收者耗时: %v\n", valueTime)
|
||||
fmt.Printf(" 指针接收者耗时: %v\n", pointerTime)
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateMethodSets 演示方法集和接口实现
|
||||
func demonstrateMethodSets() {
|
||||
fmt.Println("3. 方法集和接口实现:")
|
||||
|
||||
// 接口实现
|
||||
fmt.Printf(" 接口实现:\n")
|
||||
|
||||
var shapes []Shape
|
||||
shapes = append(shapes, Rectangle{Width: 4, Height: 3})
|
||||
shapes = append(shapes, Circle{Radius: 2})
|
||||
shapes = append(shapes, Triangle{Base: 6, Height: 4})
|
||||
|
||||
totalArea := 0.0
|
||||
for i, shape := range shapes {
|
||||
area := shape.Area()
|
||||
fmt.Printf(" 形状 %d 面积: %.2f\n", i+1, area)
|
||||
totalArea += area
|
||||
}
|
||||
fmt.Printf(" 总面积: %.2f\n", totalArea)
|
||||
|
||||
// 方法集的规则
|
||||
fmt.Printf(" 方法集的规则:\n")
|
||||
|
||||
// 值类型的方法集
|
||||
var drawable1 Drawable = Rectangle{Width: 5, Height: 3}
|
||||
drawable1.Draw()
|
||||
|
||||
// 指针类型的方法集
|
||||
rect := Rectangle{Width: 5, Height: 3}
|
||||
var drawable2 Drawable = &rect
|
||||
drawable2.Draw()
|
||||
|
||||
// 可修改接口
|
||||
fmt.Printf(" 可修改接口:\n")
|
||||
|
||||
var modifiable Modifiable = &rect
|
||||
fmt.Printf(" 修改前: %+v\n", rect)
|
||||
modifiable.Modify()
|
||||
fmt.Printf(" 修改后: %+v\n", rect)
|
||||
|
||||
// 注意:值类型不能实现需要指针接收者的接口
|
||||
// var modifiable2 Modifiable = rect // 编译错误
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateMethodComposition 演示方法的继承和组合
|
||||
func demonstrateMethodComposition() {
|
||||
fmt.Println("4. 方法的继承和组合:")
|
||||
|
||||
// 结构体嵌入
|
||||
fmt.Printf(" 结构体嵌入:\n")
|
||||
|
||||
person := Person{
|
||||
Name: "Alice",
|
||||
Age: 30,
|
||||
}
|
||||
|
||||
employee := Employee{
|
||||
Person: person,
|
||||
JobTitle: "软件工程师",
|
||||
Salary: 80000,
|
||||
}
|
||||
|
||||
// 可以直接调用嵌入类型的方法
|
||||
fmt.Printf(" 员工信息: %s\n", employee.GetInfo())
|
||||
fmt.Printf(" 员工详情: %s\n", employee.GetDetails())
|
||||
|
||||
// 匿名嵌入
|
||||
fmt.Printf(" 匿名嵌入:\n")
|
||||
|
||||
manager := Manager{
|
||||
Person: Person{
|
||||
Name: "Bob",
|
||||
Age: 35,
|
||||
},
|
||||
Department: "技术部",
|
||||
TeamSize: 10,
|
||||
}
|
||||
|
||||
// 直接访问嵌入类型的方法和字段
|
||||
fmt.Printf(" 经理姓名: %s\n", manager.Name) // 直接访问嵌入字段
|
||||
fmt.Printf(" 经理信息: %s\n", manager.GetInfo()) // 直接调用嵌入方法
|
||||
fmt.Printf(" 管理信息: %s\n", manager.Manage())
|
||||
|
||||
// 方法重写
|
||||
fmt.Printf(" 方法重写:\n")
|
||||
|
||||
student := Student{
|
||||
Person: Person{
|
||||
Name: "Charlie",
|
||||
Age: 20,
|
||||
},
|
||||
School: "清华大学",
|
||||
Grade: "大三",
|
||||
}
|
||||
|
||||
// Student 重写了 GetInfo 方法
|
||||
fmt.Printf(" 学生信息: %s\n", student.GetInfo())
|
||||
|
||||
// 仍然可以访问原始方法
|
||||
fmt.Printf(" 基础信息: %s\n", student.Person.GetInfo())
|
||||
|
||||
fmt.Println()
|
||||
}// dem
|
||||
onstratePracticalApplications 演示方法的实际应用
|
||||
func demonstratePracticalApplications() {
|
||||
fmt.Println("5. 方法的实际应用:")
|
||||
|
||||
// 应用1: 银行账户管理
|
||||
fmt.Printf(" 应用1 - 银行账户管理:\n")
|
||||
|
||||
account := BankAccount{
|
||||
AccountNumber: "123456789",
|
||||
Balance: 1000.0,
|
||||
Owner: "Alice",
|
||||
}
|
||||
|
||||
fmt.Printf(" 初始账户: %s\n", account.GetInfo())
|
||||
|
||||
account.Deposit(500.0)
|
||||
fmt.Printf(" 存款后: %s\n", account.GetInfo())
|
||||
|
||||
success := account.Withdraw(200.0)
|
||||
fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance)
|
||||
|
||||
success = account.Withdraw(2000.0)
|
||||
fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance)
|
||||
|
||||
// 应用2: 购物车系统
|
||||
fmt.Printf(" 应用2 - 购物车系统:\n")
|
||||
|
||||
cart := ShoppingCart{}
|
||||
|
||||
cart.AddItem("笔记本电脑", 5999.99, 1)
|
||||
cart.AddItem("鼠标", 99.99, 2)
|
||||
cart.AddItem("键盘", 299.99, 1)
|
||||
|
||||
fmt.Printf(" 购物车内容:\n")
|
||||
cart.DisplayItems()
|
||||
|
||||
fmt.Printf(" 总价: %.2f\n", cart.GetTotal())
|
||||
|
||||
cart.RemoveItem("鼠标")
|
||||
fmt.Printf(" 移除鼠标后总价: %.2f\n", cart.GetTotal())
|
||||
|
||||
// 应用3: 日志记录器
|
||||
fmt.Printf(" 应用3 - 日志记录器:\n")
|
||||
|
||||
logger := Logger{Level: "INFO"}
|
||||
|
||||
logger.Info("应用程序启动")
|
||||
logger.Warning("配置文件使用默认值")
|
||||
logger.Error("数据库连接失败")
|
||||
logger.Debug("调试信息") // 不会显示,因为级别是 INFO
|
||||
|
||||
logger.SetLevel("DEBUG")
|
||||
logger.Debug("现在可以看到调试信息了")
|
||||
|
||||
// 应用4: 配置管理器
|
||||
fmt.Printf(" 应用4 - 配置管理器:\n")
|
||||
|
||||
config := Config{
|
||||
settings: make(map[string]string),
|
||||
}
|
||||
|
||||
config.Set("database.host", "localhost")
|
||||
config.Set("database.port", "5432")
|
||||
config.Set("app.debug", "true")
|
||||
|
||||
fmt.Printf(" 数据库主机: %s\n", config.Get("database.host"))
|
||||
fmt.Printf(" 应用调试: %s\n", config.Get("app.debug"))
|
||||
fmt.Printf(" 不存在的配置: %s\n", config.Get("nonexistent"))
|
||||
|
||||
fmt.Printf(" 所有配置:\n")
|
||||
config.DisplayAll()
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// demonstrateAdvancedMethodUsage 演示方法的高级用法
|
||||
func demonstrateAdvancedMethodUsage() {
|
||||
fmt.Println("6. 方法的高级用法:")
|
||||
|
||||
// 高级用法1: 方法表达式
|
||||
fmt.Printf(" 高级用法1 - 方法表达式:\n")
|
||||
|
||||
rect := Rectangle{Width: 4, Height: 3}
|
||||
|
||||
// 方法表达式:将方法转换为函数
|
||||
areaFunc := Rectangle.Area
|
||||
perimeterFunc := Rectangle.Perimeter
|
||||
|
||||
fmt.Printf(" 使用方法表达式计算面积: %.2f\n", areaFunc(rect))
|
||||
fmt.Printf(" 使用方法表达式计算周长: %.2f\n", perimeterFunc(rect))
|
||||
|
||||
// 高级用法2: 方法值
|
||||
fmt.Printf(" 高级用法2 - 方法值:\n")
|
||||
|
||||
// 方法值:绑定到特定实例的方法
|
||||
rectAreaMethod := rect.Area
|
||||
rectPerimeterMethod := rect.Perimeter
|
||||
|
||||
fmt.Printf(" 使用方法值计算面积: %.2f\n", rectAreaMethod())
|
||||
fmt.Printf(" 使用方法值计算周长: %.2f\n", rectPerimeterMethod())
|
||||
|
||||
// 高级用法3: 接口组合
|
||||
fmt.Printf(" 高级用法3 - 接口组合:\n")
|
||||
|
||||
var readWriter ReadWriter = &File{Name: "test.txt"}
|
||||
|
||||
data := []byte("Hello, World!")
|
||||
readWriter.Write(data)
|
||||
|
||||
buffer := make([]byte, 20)
|
||||
n := readWriter.Read(buffer)
|
||||
fmt.Printf(" 读取到 %d 字节: %s\n", n, string(buffer[:n]))
|
||||
|
||||
// 高级用法4: 类型断言和方法调用
|
||||
fmt.Printf(" 高级用法4 - 类型断言和方法调用:\n")
|
||||
|
||||
var shape Shape = Circle{Radius: 5}
|
||||
|
||||
// 类型断言获取具体类型
|
||||
if circle, ok := shape.(Circle); ok {
|
||||
fmt.Printf(" 圆的半径: %.2f\n", circle.Radius)
|
||||
fmt.Printf(" 圆的周长: %.2f\n", circle.Circumference())
|
||||
}
|
||||
|
||||
// 高级用法5: 方法集的动态调用
|
||||
fmt.Printf(" 高级用法5 - 方法集的动态调用:\n")
|
||||
|
||||
calculator := Calculator{}
|
||||
|
||||
operations := []struct {
|
||||
name string
|
||||
method func(float64, float64) float64
|
||||
}{
|
||||
{"加法", calculator.Add},
|
||||
{"减法", calculator.Subtract},
|
||||
{"乘法", calculator.Multiply},
|
||||
{"除法", calculator.Divide},
|
||||
}
|
||||
|
||||
a, b := 10.0, 3.0
|
||||
for _, op := range operations {
|
||||
result := op.method(a, b)
|
||||
fmt.Printf(" %.1f %s %.1f = %.2f\n", a, op.name, b, result)
|
||||
}
|
||||
|
||||
// 高级用法6: 链式方法调用
|
||||
fmt.Printf(" 高级用法6 - 链式方法调用:\n")
|
||||
|
||||
builder := NewStringBuilder()
|
||||
result := builder.
|
||||
Append("Hello").
|
||||
Append(" ").
|
||||
Append("World").
|
||||
Append("!").
|
||||
ToUpper().
|
||||
Build()
|
||||
|
||||
fmt.Printf(" 构建结果: %s\n", result)
|
||||
|
||||
fmt.Println()
|
||||
}// =
|
||||
========= 类型和方法定义 ==========
|
||||
|
||||
// 基本结构体和方法
|
||||
type Rectangle struct {
|
||||
Width float64
|
||||
Height float64
|
||||
}
|
||||
|
||||
func (r Rectangle) Area() float64 {
|
||||
return r.Width * r.Height
|
||||
}
|
||||
|
||||
func (r Rectangle) Perimeter() float64 {
|
||||
return 2 * (r.Width + r.Height)
|
||||
}
|
||||
|
||||
// 指针接收者方法,支持方法链
|
||||
func (r *Rectangle) SetWidth(width float64) *Rectangle {
|
||||
r.Width = width
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rectangle) SetHeight(height float64) *Rectangle {
|
||||
r.Height = height
|
||||
return r
|
||||
}
|
||||
|
||||
func (r Rectangle) Draw() {
|
||||
fmt.Printf(" 绘制矩形: %.1f x %.1f\n", r.Width, r.Height)
|
||||
}
|
||||
|
||||
func (r *Rectangle) Modify() {
|
||||
r.Width *= 1.1
|
||||
r.Height *= 1.1
|
||||
fmt.Printf(" 矩形已放大 10%%\n")
|
||||
}
|
||||
|
||||
// 圆形结构体和方法
|
||||
type Circle struct {
|
||||
Radius float64
|
||||
}
|
||||
|
||||
func (c Circle) Area() float64 {
|
||||
return math.Pi * c.Radius * c.Radius
|
||||
}
|
||||
|
||||
func (c Circle) Circumference() float64 {
|
||||
return 2 * math.Pi * c.Radius
|
||||
}
|
||||
|
||||
func (c Circle) Draw() {
|
||||
fmt.Printf(" 绘制圆形: 半径 %.1f\n", c.Radius)
|
||||
}
|
||||
|
||||
// 三角形结构体和方法
|
||||
type Triangle struct {
|
||||
Base float64
|
||||
Height float64
|
||||
}
|
||||
|
||||
func (t Triangle) Area() float64 {
|
||||
return 0.5 * t.Base * t.Height
|
||||
}
|
||||
|
||||
func (t Triangle) Draw() {
|
||||
fmt.Printf(" 绘制三角形: 底边 %.1f, 高 %.1f\n", t.Base, t.Height)
|
||||
}
|
||||
|
||||
// 基本类型的方法
|
||||
type Temperature float64
|
||||
|
||||
func (t Temperature) ToFahrenheit() float64 {
|
||||
return float64(t)*9/5 + 32
|
||||
}
|
||||
|
||||
func (t Temperature) ToKelvin() float64 {
|
||||
return float64(t) + 273.15
|
||||
}
|
||||
|
||||
// 值接收者 vs 指针接收者示例
|
||||
type Counter struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
// 值接收者:不会修改原始值
|
||||
func (c Counter) IncrementByValue() {
|
||||
c.Value++
|
||||
fmt.Printf(" 值接收者内部: %d\n", c.Value)
|
||||
}
|
||||
|
||||
// 指针接收者:会修改原始值
|
||||
func (c *Counter) IncrementByPointer() {
|
||||
c.Value++
|
||||
fmt.Printf(" 指针接收者内部: %d\n", c.Value)
|
||||
}
|
||||
|
||||
func (c Counter) GetValueCopy() int {
|
||||
return c.Value
|
||||
}
|
||||
|
||||
// 大结构体性能测试
|
||||
type LargeStruct struct {
|
||||
Data [1000]int
|
||||
}
|
||||
|
||||
func (ls LargeStruct) ProcessByValue() {
|
||||
// 值接收者会拷贝整个结构体
|
||||
sum := 0
|
||||
for _, v := range ls.Data {
|
||||
sum += v
|
||||
}
|
||||
}
|
||||
|
||||
func (ls *LargeStruct) ProcessByPointer() {
|
||||
// 指针接收者只传递指针
|
||||
sum := 0
|
||||
for _, v := range ls.Data {
|
||||
sum += v
|
||||
}
|
||||
}
|
||||
|
||||
// 接口定义
|
||||
type Shape interface {
|
||||
Area() float64
|
||||
}
|
||||
|
||||
type Drawable interface {
|
||||
Draw()
|
||||
}
|
||||
|
||||
type Modifiable interface {
|
||||
Modify()
|
||||
}
|
||||
|
||||
// 组合接口
|
||||
type ReadWriter interface {
|
||||
Reader
|
||||
Writer
|
||||
}
|
||||
|
||||
type Reader interface {
|
||||
Read([]byte) int
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write([]byte) int
|
||||
}
|
||||
|
||||
// 文件类型实现 ReadWriter 接口
|
||||
type File struct {
|
||||
Name string
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (f *File) Read(buffer []byte) int {
|
||||
n := copy(buffer, f.data)
|
||||
return n
|
||||
}
|
||||
|
||||
func (f *File) Write(data []byte) int {
|
||||
f.data = append(f.data, data...)
|
||||
return len(data)
|
||||
}
|
||||
|
||||
// 结构体嵌入示例
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func (p Person) GetInfo() string {
|
||||
return fmt.Sprintf("%s (%d岁)", p.Name, p.Age)
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Person // 具名嵌入
|
||||
JobTitle string
|
||||
Salary float64
|
||||
}
|
||||
|
||||
func (e Employee) GetDetails() string {
|
||||
return fmt.Sprintf("%s - %s, 薪资: %.0f", e.GetInfo(), e.JobTitle, e.Salary)
|
||||
}
|
||||
|
||||
// 匿名嵌入
|
||||
type Manager struct {
|
||||
Person // 匿名嵌入
|
||||
Department string
|
||||
TeamSize int
|
||||
}
|
||||
|
||||
func (m Manager) Manage() string {
|
||||
return fmt.Sprintf("管理 %s,团队规模: %d人", m.Department, m.TeamSize)
|
||||
}
|
||||
|
||||
// 方法重写示例
|
||||
type Student struct {
|
||||
Person
|
||||
School string
|
||||
Grade string
|
||||
}
|
||||
|
||||
// 重写 Person 的 GetInfo 方法
|
||||
func (s Student) GetInfo() string {
|
||||
return fmt.Sprintf("%s (%d岁) - %s %s", s.Name, s.Age, s.School, s.Grade)
|
||||
}// 实际应用
|
||||
示例
|
||||
|
||||
// 银行账户
|
||||
type BankAccount struct {
|
||||
AccountNumber string
|
||||
Balance float64
|
||||
Owner string
|
||||
}
|
||||
|
||||
func (ba *BankAccount) Deposit(amount float64) {
|
||||
if amount > 0 {
|
||||
ba.Balance += amount
|
||||
fmt.Printf(" 存款 %.2f,当前余额: %.2f\n", amount, ba.Balance)
|
||||
}
|
||||
}
|
||||
|
||||
func (ba *BankAccount) Withdraw(amount float64) bool {
|
||||
if amount > 0 && amount <= ba.Balance {
|
||||
ba.Balance -= amount
|
||||
fmt.Printf(" 取款 %.2f,当前余额: %.2f\n", amount, ba.Balance)
|
||||
return true
|
||||
}
|
||||
fmt.Printf(" 取款失败:余额不足或金额无效\n")
|
||||
return false
|
||||
}
|
||||
|
||||
func (ba BankAccount) GetInfo() string {
|
||||
return fmt.Sprintf("账户: %s, 户主: %s, 余额: %.2f",
|
||||
ba.AccountNumber, ba.Owner, ba.Balance)
|
||||
}
|
||||
|
||||
// 购物车系统
|
||||
type CartItem struct {
|
||||
Name string
|
||||
Price float64
|
||||
Quantity int
|
||||
}
|
||||
|
||||
type ShoppingCart struct {
|
||||
Items []CartItem
|
||||
}
|
||||
|
||||
func (sc *ShoppingCart) AddItem(name string, price float64, quantity int) {
|
||||
// 检查是否已存在该商品
|
||||
for i := range sc.Items {
|
||||
if sc.Items[i].Name == name {
|
||||
sc.Items[i].Quantity += quantity
|
||||
return
|
||||
}
|
||||
}
|
||||
// 添加新商品
|
||||
sc.Items = append(sc.Items, CartItem{
|
||||
Name: name,
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
})
|
||||
}
|
||||
|
||||
func (sc *ShoppingCart) RemoveItem(name string) {
|
||||
for i, item := range sc.Items {
|
||||
if item.Name == name {
|
||||
sc.Items = append(sc.Items[:i], sc.Items[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sc ShoppingCart) GetTotal() float64 {
|
||||
total := 0.0
|
||||
for _, item := range sc.Items {
|
||||
total += item.Price * float64(item.Quantity)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func (sc ShoppingCart) DisplayItems() {
|
||||
for _, item := range sc.Items {
|
||||
fmt.Printf(" %s: %.2f × %d = %.2f\n",
|
||||
item.Name, item.Price, item.Quantity,
|
||||
item.Price*float64(item.Quantity))
|
||||
}
|
||||
}
|
||||
|
||||
// 日志记录器
|
||||
type Logger struct {
|
||||
Level string
|
||||
}
|
||||
|
||||
func (l *Logger) SetLevel(level string) {
|
||||
l.Level = level
|
||||
}
|
||||
|
||||
func (l Logger) shouldLog(level string) bool {
|
||||
levels := map[string]int{
|
||||
"DEBUG": 0,
|
||||
"INFO": 1,
|
||||
"WARN": 2,
|
||||
"ERROR": 3,
|
||||
}
|
||||
|
||||
currentLevel := levels[l.Level]
|
||||
messageLevel := levels[level]
|
||||
|
||||
return messageLevel >= currentLevel
|
||||
}
|
||||
|
||||
func (l Logger) log(level, message string) {
|
||||
if l.shouldLog(level) {
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05")
|
||||
fmt.Printf(" [%s] %s: %s\n", timestamp, level, message)
|
||||
}
|
||||
}
|
||||
|
||||
func (l Logger) Debug(message string) {
|
||||
l.log("DEBUG", message)
|
||||
}
|
||||
|
||||
func (l Logger) Info(message string) {
|
||||
l.log("INFO", message)
|
||||
}
|
||||
|
||||
func (l Logger) Warning(message string) {
|
||||
l.log("WARN", message)
|
||||
}
|
||||
|
||||
func (l Logger) Error(message string) {
|
||||
l.log("ERROR", message)
|
||||
}
|
||||
|
||||
// 配置管理器
|
||||
type Config struct {
|
||||
settings map[string]string
|
||||
}
|
||||
|
||||
func (c *Config) Set(key, value string) {
|
||||
c.settings[key] = value
|
||||
}
|
||||
|
||||
func (c Config) Get(key string) string {
|
||||
if value, exists := c.settings[key]; exists {
|
||||
return value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c Config) DisplayAll() {
|
||||
for key, value := range c.settings {
|
||||
fmt.Printf(" %s = %s\n", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 计算器
|
||||
type Calculator struct{}
|
||||
|
||||
func (calc Calculator) Add(a, b float64) float64 {
|
||||
return a + b
|
||||
}
|
||||
|
||||
func (calc Calculator) Subtract(a, b float64) float64 {
|
||||
return a - b
|
||||
}
|
||||
|
||||
func (calc Calculator) Multiply(a, b float64) float64 {
|
||||
return a * b
|
||||
}
|
||||
|
||||
func (calc Calculator) Divide(a, b float64) float64 {
|
||||
if b != 0 {
|
||||
return a / b
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 字符串构建器(链式调用)
|
||||
type StringBuilder struct {
|
||||
parts []string
|
||||
}
|
||||
|
||||
func NewStringBuilder() *StringBuilder {
|
||||
return &StringBuilder{parts: make([]string, 0)}
|
||||
}
|
||||
|
||||
func (sb *StringBuilder) Append(str string) *StringBuilder {
|
||||
sb.parts = append(sb.parts, str)
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *StringBuilder) ToUpper() *StringBuilder {
|
||||
for i, part := range sb.parts {
|
||||
sb.parts[i] = strings.ToUpper(part)
|
||||
}
|
||||
return sb
|
||||
}
|
||||
|
||||
func (sb *StringBuilder) Build() string {
|
||||
return strings.Join(sb.parts, "")
|
||||
}
|
||||
|
||||
/*
|
||||
运行这个程序:
|
||||
go run 05-methods.go
|
||||
|
||||
学习要点:
|
||||
1. 方法是与特定类型关联的函数
|
||||
2. 方法定义语法:func (receiver Type) MethodName() ReturnType
|
||||
3. 值接收者和指针接收者有不同的行为和用途
|
||||
4. 方法集决定了类型可以实现哪些接口
|
||||
5. 结构体嵌入可以实现方法的继承和组合
|
||||
|
||||
方法 vs 函数:
|
||||
1. 方法有接收者,函数没有
|
||||
2. 方法属于特定类型,函数是独立的
|
||||
3. 方法可以访问接收者的字段和其他方法
|
||||
4. 方法支持多态(通过接口)
|
||||
|
||||
接收者类型选择:
|
||||
1. 值接收者:
|
||||
- 不需要修改接收者
|
||||
- 接收者是小的结构体
|
||||
- 接收者是基本类型、数组或小的结构体
|
||||
|
||||
2. 指针接收者:
|
||||
- 需要修改接收者
|
||||
- 接收者是大的结构体(避免拷贝)
|
||||
- 接收者包含不能拷贝的字段(如 sync.Mutex)
|
||||
|
||||
方法集规则:
|
||||
1. 值类型 T 的方法集:所有值接收者方法
|
||||
2. 指针类型 *T 的方法集:所有值接收者和指针接收者方法
|
||||
3. 接口实现需要考虑方法集的匹配
|
||||
|
||||
最佳实践:
|
||||
1. 保持接收者类型的一致性
|
||||
2. 优先使用指针接收者(除非有特殊原因)
|
||||
3. 合理使用结构体嵌入实现代码复用
|
||||
4. 设计清晰的接口和方法签名
|
||||
5. 使用方法实现面向对象的设计模式
|
||||
|
||||
常见应用场景:
|
||||
1. 数据封装和操作
|
||||
2. 业务逻辑实现
|
||||
3. 接口实现和多态
|
||||
4. 链式调用和流畅接口
|
||||
5. 状态管理
|
||||
6. 配置和选项处理
|
||||
|
||||
高级特性:
|
||||
1. 方法表达式和方法值
|
||||
2. 接口组合
|
||||
3. 类型断言
|
||||
4. 动态方法调用
|
||||
5. 链式方法调用
|
||||
*/
|
16
golang-learning/03-functions/README.md
Normal file
16
golang-learning/03-functions/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 第三章:函数和方法
|
||||
|
||||
本章将学习 Go 语言的函数定义、调用以及方法的概念。
|
||||
|
||||
## 学习目标
|
||||
- 掌握函数的定义和调用
|
||||
- 理解多返回值的概念
|
||||
- 学会使用可变参数
|
||||
- 了解闭包和方法
|
||||
|
||||
## 文件列表
|
||||
- `01-basic-functions.go` - 基础函数
|
||||
- `02-multiple-returns.go` - 多返回值
|
||||
- `03-variadic-functions.go` - 可变参数函数
|
||||
- `04-closures.go` - 闭包
|
||||
- `05-methods.go` - 方法
|
Reference in New Issue
Block a user