Go 函数
函数是 Go 的核心。Go 函数使用 func 开头,可以使用零或多个参数,可以返回一个参数,或者使用元组包装多个参数。Go 需要明确的 return,也就是说,它不会自动 return 最后一个表达式的值。
当多个连续的参数为同样类型时,可以仅声明最后一个参数的类型,忽略之前相同类型参数的类型声明。
Go 原生支持多返回值,如果需要返回多个值,可以使用元组来表示,例如(int,int)在函数中表示返回 2 个 int。在调用函数时,如果仅仅需要返回值的一部分的话,可以使用空白标识符_。
可变参数函数。在调用时可以传入任意数量的参数。使用…来表示,例如:
func sum(nums ...int) {
// 实现逻辑
}
这个函数可以接受任意数量的 int 作为参数。
Go 支持匿名函数,并能用其构造闭包。匿名函数在你想定义一个不需要命名的内联函数时非常有用。
func intSeq() func() int{
i:=0
return func() int{
i++
return i
}
}
intSeq 函数返回一个在其函数体内定义的匿名函数。返回的函数使用闭包的方式隐藏变量 i。返回的函数隐藏变量 i 以形成闭包。
我们可以这样调用:
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
我们调用 intSeq 函数,将返回值(一个函数)赋给 nextInt。这个函数的值包含了自己的值 i,这样在每次调用 nextInt 时,都会更新 i 的值。
Go 支持递归,例如:
func fact(n int) int {
if n == 0 {
return 1
}
return n * fact(n-1)
}
这个 fact 函数在到达 fact(0)前一直调用自身。
闭包也是可以递归的,但这要求在定义闭包之前用类型化的 var 显式声明闭包。例如这样:
var fib func(n int) int
fib = func(n int) int {
if n < 2 {
return n
}
return fib(n-1) + fib(n-2)
}
fmt.Println(fib(7))
如果需要先定义,然后在 return 前返回需要添加 defer 关键字。
下面的一段代码,获取几个整型参数经计算后再返回一个整型值:
package main
import (
"math/bits"
)
// 相同的质数表(确保与Rust一致)
var primes = [4]int64{
0x7F4A7C15, // 32位质数
0x9E3779B9, // 黄金分割质数
0xABCDEF01, // 自定义大质数
0x123456789ABCDEF, // 64位质数
}
// 计算d值(与Rust完全一致)
func CalculateD(a, b, nonce, deviceID int64) int64 {
// 1. 动态选择质数(错误写法)
prime := primes[(a^deviceID)%4]
if (a^deviceID)%4 < 0 { // 处理负数取模
prime = primes[((a^deviceID)%4)+4]
}
// 1. 安全选择质数
index := (a ^ deviceID) % 4
if index < 0 {
index += 4
}
prime := primes[index]
// 2. 多阶段混淆计算
stage1 := a * prime ^ nonce // 乘法+异或
stage2 := rotateLeft(b+deviceID, 17) // 加法+循环左移
stage3 := (stage1 + stage2) * prime // 混合叠加
// 3. 约束到正数范围(同Rust的% 0x7FFFFFFFFFFFFFFF)
return stage3 & 0x7FFFFFFFFFFFFFFF
}
// 循环左移(Go无内置操作,需手动实现)
func rotateLeft(n int64, shift uint) int64 {
shift %= 64
return (n << shift) | (n >> (64 - shift))
}
// 验证函数(比较Rust和Go的结果)
func Verify(a, b, nonce, deviceID int64, rustResult int64) bool {
return CalculateD(a, b, nonce, deviceID) == rustResult
}
还有一个比较特殊的是函数闭包,Go 函数可以是闭包。闭包是指引用了其外部作用域变量的函数值。该函数可以访问并修改这些引用的变量;从这个意义上说,函数与这些变量是“绑定”的。
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
通关密语:func