一、函数

函数声明

// 声明语法: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)

go 学习 (三):函数 & 指针 & 结构体的更多相关文章

  1. 【AT91SAM3S】SAM3S-EK Demo工程中,LCD驱动程序的加载(函数指针结构体)

    为了调试LCD,在英倍特的板子上烧Atmel的sam3s-ek_demo_1.4_source示例代码.LCD显示正常了,却找不到LCD的驱动究竟在哪. 花了好久,追踪到了这个执行过程. 进入main ...

  2. C语言笔记 08_函数指针&回调函数&字符串&结构体&位域

    函数指针 函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调用函数.传递参数. 函数指针变量的声明: / ...

  3. 【C++】结构体/结构体数组/结构体指针/结构体嵌套/函数参数/const

    一.结构体声明 struct Student { //成员列表 string name; int age; int score; }; //s3;定义时直接声明 int main() { struct ...

  4. Go-常识补充-切片-map(类似字典)-字符串-指针-结构体

    目录 Go 常识补充 Go 命名 打印变量类型科普 _ 关键字 命名规范相关 包目录规范 切片 多维切片 切片初始化的方法 多维切片初始化 切片删除元素(会略微影响效率 ,少用) copy 函数 打散 ...

  5. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  6. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  7. matlab学习笔记12_3串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields

    一起来学matlab-matlab学习笔记12 12_3 结构体 串联结构体,按属性创建含有元胞数组的结构体,filenames,isfield,isstruct,orderfields 觉得有用的话 ...

  8. C++学习之函数指针

     C++学习之函数指针          和数据项类似,函数也有地址,函数的地址是存储在机器语言代码的内存的开始地址.通常,这些地址对用户而言,不重要也没什么用处,但对程序而言,它却很有用. 一.函数 ...

  9. c的详细学习(9)结构体与共用体的学习(一)

    C语言提供了另外两种构造类型:结构体与公用体,用来存储若干个类型不同但彼此组成一个集合的数据总体. (1)结构体类型与结构体变量 1.定义 其一般形式为: struct  结构体类型名{ 数据类型1 ...

随机推荐

  1. Python代码约定

    建议遵守以下约定: 使用 4 个空格来缩进 永远不要混用空格和制表符 在函数之间空一行 在类之间空两行 字典,列表,元组以及参数列表中,在 , 后添加一个空格.对于字典,: 后面也添加一个空格 在赋值 ...

  2. C++ 二叉搜索树原理及其实现

    首先是概念:二叉搜索树又称二叉排序树,它具有以下的性质: 若是左子树不为空,则左子树上所有节点的值小于根节点的值 若是右子树不为空,则右子树上所有结点的值大于根节点的值 二叉搜索树的左右子树也是二叉搜 ...

  3. Django-12-auth认证组件

    1. 介绍 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能. Django作为一个完美主义者的终极框架,当然也会 ...

  4. C语言基础知识---认识C语言

    2019.11.09 秋风 晴 最近一直在搞一套LoRa算法.总算有点效果了.心感慰藉(可能用错词语.但是也不管了) 初学者如何理解C语言? 无需刻板理解,笔者常用一个这样的例子助学生理解:法国人和法 ...

  5. Oracle--(Hierarchical Queries)层级查询(用于部门层级等)

    原网址:https://www.cnblogs.com/guofeiji/p/5291486.html 如果表中包含层级数据,可以使用层级查询子句按层级顺序选择数据行,形成层级树,形式如下: 下面是层 ...

  6. docker redis4.0集群搭建

    一.前言 redis集群对于很多人来说非常熟悉,在前些日子,我也有一位大兄弟也发布过一篇关于在阿里云(centOS7)上搭建redis 集群的文章,虽然集群搭建的文章在网上很多,我比较喜欢这篇文章的地 ...

  7. pytest_01-环境准备与入门

    前言 首先说下为什么要学pytest,在此之前相信大家已经掌握了python里面的unittest单元测试框架,那再学一个框架肯定是需要学习时间成本的. 刚开始我的内心是拒绝的,我想我用unittes ...

  8. 在部署 C#项目时转换 App.config 配置文件

    问题 部署项目时,常常需要根据不同的环境使用不同的配置文件.例如,在部署网站时可能希望禁用调试选项,并更改连接字符串以使其指向不同的数据库.在创建 Web 项目时,Visual Studio 自动生成 ...

  9. java之hibernate之hibernate查询

    这篇主要简单间接 hibernate查询 1.数据库操作中最重要的是查询,Hibernate提供了多种查询方式来帮助程序员快速实现查询功能. 有hql,本地sql查询,Criteria查询,examp ...

  10. python 安装 SQLAlchemy 报错

    安装 SQLAlchemy 报错 安装命令 pip install -i https://pypi.doubanio.com/simple SQLAlchemy 报错截图 编码错误,这里我们需要改下源 ...