go 学习 (三):函数 & 指针 & 结构体

一、函数

函数声明

// 声明语法:Go 中函数传递的参数都是值传递(将形参的值拷贝一份给函数内部使用, 形参与实参是相互独立互不影响的),其包括普通函数、lambda函数(匿名函数)、方法
 func 函数名(参数) 返回值 {
   函数体
 } // eg: 斐波那契数列(递归)
func fibonacci(n int) int {
if n < {
return n
} else {
return fibonacci(n-) + fibonacci(n-)
}
}

函数返回值

// 一个返回值的函数
func max(num1 int, num2 int) int {
if num1 > num2 {
return num1
} else {
return num2
}
} // 多个返回值的函数
func allValue(num int, name string) (int, string) {
fmt.Println("In allValue function num: ", num)
fmt.Println("In allValue function name: " + name)
return num, name
} func main() {
num1 :=
num2 :=
result := max(num1, num2)
fmt.Println("result: ", result) num, name := allValue(num2, "power")
fmt.Println("In main function num: ", num)
fmt.Println("In main function name: ", name) }

函数参数

  • 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
func valueFunc(num1 int, num2 int) {
num1, num2 = num2, num1
} // 当参数中多个参数类型一致时, 可简写参数的类型
func f1(x, y int, m, n string, i, j bool) int {
return x + y
} func main() {
fmt.Println("值传递交换前 num1 的值: ", num1)
fmt.Println("值传递交换前 num2 的值: ", num2)
valueFunc(num1, num2)
fmt.Println("值传递交换后 num1 的值: ", num1)
fmt.Println("值传递交换后 num2 的值: ", num2)
} // [Output]:值传递交换前 num1 的值: 20
// [Output]:值传递交换前 num2 的值: 10
// [Output]:值传递交换后 num1 的值: 20
// [Output]:值传递交换后 num2 的值: 10
  • 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
func pointFunc(prt1 *int, prt2 *int) {
*prt1, *prt2 = *prt2, *prt1
} func main(){
num1, num2 := ,
var prt1 *int = &num1
var prt2 *int = &num2 fmt.Println("交换前 num1 的值: ", num1)
fmt.Println("交换前 num2 的值: ", num2)
pointFunc(prt1, prt2) // 指针作为函数参数,传递的是参数的地址
fmt.Println("交换后 num1 的值: ", num1)
fmt.Println("交换后 num2 的值: ", num2)
} // [Output]: 交换前 num1 的值: 10
// [Output]: 交换前 num2 的值: 20
// [Output]: 交换后 num1 的值: 20
// [Output]: 交换后 num2 的值: 10
  • 默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

可变参数:必须放在函数参数的最后, Go 语言中没有默认参数概念

// 接收相同类型的可变参数的函数
func argsSameFunc(args ... string) {
fmt.Print("same type elem: ")
for _, param := range args {
fmt.Print(param, ", ")
}
fmt.Println()
} // 接受不同类型的可变参数的函数
func argsDifferenceFunc(args ... interface{}) {
fmt.Print("difference type elem: ")
for _, param := range args {
fmt.Print(param, ",")
}
fmt.Print("\n")
} // 接收可变数量的参数, 类型约束为字符串
func joinStrings(slist ...string) string {
// 定义一个字节缓冲, 快速地连接字符串
var b bytes.Buffer
// 遍历可变参数列表slist, 类型为[]string
for _, s := range slist {
// 将遍历出的字符串连续写入字节数组
b.WriteString(s)
}
// 将连接好的字节数组转换为字符串并输出
return b.String()
} func main() { // 接受相同类型的可变参数函数
argsSameFunc("power")
argsSameFunc("forever", "topOne")
argsSameFunc("selina", "hebe", "ella") // 接受不同类型的可变参数函数
argsDifferenceFunc("power", )
argsDifferenceFunc("selina", , "hebe", , "ella", )   fmt.Println(joinStrings("Asia ", "sky", " crops:", "S.H.E"))
  fmt.Println(joinStrings("They ", "gave ", "me ", "the ", "courage "))
  fmt.Print(reflect.TypeOf(num1))    // 可获取变量的类型
}

函数作为参数、返回值

// 函数作为参数传递
func calc(x, y int, op func(int, int) int) int { // 接收两个int类型的参数, 和 一个拥有 2个int类型参数、1个int类型返回值的函数类型 参数
return op(x, y)
}

// 函数作为返回值
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "-":
return sub, nil
default:
err := errors.New("无法识别的操作符")
return nil, err
} }
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}

全局、局部变量

、全局变量:定义在函数外部的变量, 在程序的整个运行周期内都有效, 在函数中可访问到全局变量。
、局部变量: 分为两种, 第一种 函数内定义的变量无法在该函数外使用; 如果局部变量和全局变量重名,优先访问局部变量
、局部变量: 第二种 语句块内定义的变量只能在语句块中生效(if、for、switch)

闭包

// 闭包: 闭包是一个函数 它包含这个函数 和 它外部作用域的变量(与其相关的引用环境) 组合而成的实体, 闭包=函数+引用环境; 底层原理: 函数可作为返回值; 函数内部查找变量的顺序, 先在函数内部找, 再往函数外部找

// 无参闭包
func adder() func(int) int { // 返回值的函数声明 与 return后的匿名函数 是一样的
var x int
return func(y int) int {
x += y
return x
}
} // 带参闭包
func adder2(x int) func(int) int {
return func(y int) int {
x += y
return x
}
} // 参数为函数引用的闭包
func ft(x, y int) {
fmt.Println("\nThis is ft function.")
fmt.Printf("ft(x - %v, y - %v)", x, y)
} func adders(f func(int, int), x, y int) func() {
tmp := func() {
f(x, y)
}
return tmp
} func main() { // 1、无参闭包
var f = adder() // 此时接收到的是 adder 函数返回的 匿名函数的引用
fmt.Println("closesure f(10) result: ", f()) // 此前并未给闭包内的x赋值, 所以x声明后为默认的零值, 此行代码运行过后, x已被赋值, x=0, y=10, x+=y, x=10
fmt.Println("closesure f(20) result: ", f()) // 在程序并未结束前, 前一句代码给闭包内的x所赋予的值都有效, 所以此行结果为: x=10, y=20, x+=y, x=30
var f1 = adder() // 重新赋值, 从头再来
fmt.Println("closesure f1(30) result: ", f1()) // x=0, y=30, x+=y, x=30
fmt.Println("closesure f1(50) result: ", f1()) // x=30, y=50, x+=y, x=80
fmt.Println() // 2、带参闭包
var fp = adder2() // x=10
fmt.Println("closesure fp(10) result: ", fp()) // x=10, y=10, x+=y, x=20
fmt.Println("closesure fp(30) result: ", fp()) // x=20, y=30, x+=y, x=50
var fp1 = adder2()
fmt.Println("closesure fp1(50) result: ", fp1()) // x=20, y=50, x+=y, x=70
fmt.Println("closesure fp1(20) result: ", fp1()) // x=70, y=20, x+=y, x=90 // 3、参数为函数引用的闭包
var ft1 = adders(ft, , )
ft1()
}

匿名函数

// 匿名函数: 没有函数名的函数, 它无法像普通函数那样调用, 需要将匿名函数保存到某个变量, 或作为立即执行的函数 [匿名函数多用于回调函数和闭包]
// 定义语法
func(参数列表)(返回参数列表){
// 函数体
} // 匿名函数 -- 作为执行函数(只执行一次), 函数定义完之后 加上() 将会立即执行 func(a, b int) {
fmt.Println("self excuting function a*b result: ", a*b)
}(, ) // 匿名函数 -- 作为回调函数
func visit(list []int, f func(int)) {
for _, elem := range list {
f(elem)
}
} func main() {
// 匿名函数
// 声明时调用
func(name string) {
fmt.Println("Hello ", name)
} ("power") // ---> 括号内是匿名函数执行传递的参数 // 将匿名函数赋值给变量,通过 变量() 调用
innominateFunc := func(name string) string {
fmt.Println("Hello ", name)
receiving := "Hello" + name
return receiving
}
innominateFunc("hebe") // 匿名函数作为回调函数 打印切片中的所有元素
visit([]int {, , }, func(v int) { // params: 切片,匿名函数(注意,此处的匿名函数在 visit函数的参数括号内,是作为参数传递给 visit 的)
fmt.Println(v)
})
}

方法

// 结构体
type Circle struct {
radius float64
} // 方法
func (circle Circle) method(msg string) float64 {
fmt.Println("The radius of the circle is: ", circle.radius)
return 3.14 * circle.radius * circle.radius
} func main() {
var circle Circle
circle.radius = 10.00
area := circle.method("This is a way of finding the area of a circle")
fmt.Println("The area of the circle is: ", area) fmt.Print("\n")
?

二、指针

package main

import "fmt"

const count int = 

func pointFunc(prt1 *int, prt2 *int) {
*prt1, *prt2 = *prt2, *prt1
} func main() { // 指针声明
var ip *int
var fp *float32
var ipNum int
var fpFloat float32 ipNum =
fpFloat = 3.13
// 指针赋值
ip = &ipNum
fp = &fpFloat fmt.Println("ip: ", ip)
fmt.Println("fp: ", fp) // 空指针
var prt *string
fmt.Println("prt: ", prt)
if (prt != nil){
fmt.Println("prt isn't empty pointer.")
} else {
fmt.Println("prt is empty pointer.")
} fmt.Print("\n") // 指针数组
var array = [] int{, , , , }
var ptr [count]*int
zero :=
for t:=; t<count; t++ {
ptr[t] = &array[t]
}
for r:=; r<count; r++ {
// 打印数组内元素内存地址赋值给指针数据后的所有内存地址
fmt.Print(array[r], "\t")
fmt.Print(*ptr[r], "\t")
fmt.Print(ptr[r], "\t") // 修改指针数组内所有元素的内存地址
ptr[r] = &zero
fmt.Print(ptr[r], "\t")
fmt.Println(*ptr[r])
} fmt.Print("\n") // 指向指针的指针变量
var a =
var aptr1 *int
var aptr2 **int
aptr1 = &a
aptr2 = &aptr1 fmt.Println("a value: ", a)
fmt.Println("a memory address: ", &a)
fmt.Println("aptr1 value: ", aptr1)
fmt.Println("*aptr1 value: ", *aptr1)
fmt.Println("&aptr1 memory address: ", &aptr1)
fmt.Println("aptr2 value: ", aptr2)
fmt.Println("*aptr2 value: ", *aptr2)
fmt.Println("**aptr2 value: ", **aptr2)
fmt.Println("&aptr2 memory address: ", &aptr2) fmt.Print("\n") // 指针作为函数的参数
num1, num2 := ,
var prt1 *int = &num1
var prt2 *int = &num2 fmt.Println("指针传递交换前 num1 的值: ", num1)
fmt.Println("指针传递交换前 num2 的值: ", num2)
pointFunc(prt1, prt2)
fmt.Println("指针传递交换后 num1 的值: ", num1)
fmt.Println("指针传递交换后 num2 的值: ", num2) }

三、结构体

// 声明语法
type 结构体名称 struct {
字段名1 字段1类型
字段名2 字段2类型
字段名3 字段3类型
...
} // 示例1:每行声明一个字段
type Member struct {
name string
age int
weight float64
height float32
} // 示例2:同类型字段声明在同一行
type Test struct {
one, two, three int
four string
five float32
six float64
seven bool
} // 第一种方式实例化结构体
var members Member
members.name = "power"
members.age =
members.weight = // 第二种方式实例化结构体
member := Member{"top", , , 1.65}
member := Member{"name": "top", "age": , "weight": , "height": 1.65} // 打印结构体的每个字段值
func printMemberPoint(memberPoint *Member) {
fmt.Println("memberPoint: ", memberPoint)
fmt.Println("memberPoint.name: ", memberPoint.name)
fmt.Println("memberPoint.age: ", memberPoint.age)
fmt.Println("memberPoint.weight: ", memberPoint.weight)
fmt.Println("memberPoint.height: ", memberPoint.height)
fmt.Print("\n")
}
// 第一种方式实例化指针类型的结构体:new
pointMember := new(Member)
memberPoint.name = "power"
memberPoint.age =
memberPoint.weight =
memberPoint.height = 1.73
printMemberPoint(memberPoint) // 第二种方式实例化指针类型的结构体:取址 &
memberPoint := &Member{}
memberPoint.name = "top"
memberPoint.age =
memberPoint.weight =
memberPoint.height = 1.68
printMemberPoint(memberPoint)
var memberPoint *Member
memberPoint = &members
printMemberPoint(memberPoint) // 匿名结构体
stone := struct {
nickname string
skill string
}{"small stone", "fly"}
fmt.Println("stone.nickname:", stone.nickname)
fmt.Println("stone.skill:", stone.skill)
// 结构体的方法
func (structObject *structName) method(param paramType...) (returnType...) {
  // do something }
returnValue := member.method(param)
上一篇:进程间通信IPC之--共享内存


下一篇:c#中高效的excel导入sqlserver的方法