Golang学习Day2

news2025/7/20 18:25:01

Go语言中的函数

go语言中函数特性

  1. go语言有三种函数:普通函数、匿名函数(没有名称的函数)方法(定义在struct上的函数)。receiver

  1. go语言中不运算函数重载(overload),也就是说不允许函数同名

  1. go语言中的函数不能嵌套,但是可以嵌套匿名函数

  1. 函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数

  1. 函数可以作为参数传递给另一个函数

  1. 函数的返回值可以是另一个函数

  1. 函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数

  1. 函数参数可以没有名称

go语言中函数的定义和调用

函数在使用之前必须先定义,可以调用函数来完成某个任务,函数可以重复调用,从而达到代码的复用

func function_name([parameter_list])[return_types]{
    函数体
}

package main

import "fmt"

func sum(a int, b int) (res int) {
    res = a + b
    return res
}
func main() {
    res := sum(1, 2)
    fmt.Printf("res: %v\n", res)
}
package main

import "fmt"

func compare(a int, b int) (max int) {
    if a > b {
        max = a
    } else {
        max = b
    }
    return max
}
func main() {
    res := compare(1, 2)
    fmt.Printf("res: %v\n", res)
}

go语言中的return

  1. 没有返回值

  1. 有一个返回值 (例如上面的求和以及比较两个数的大小的函数)

  1. 存在多个返回值,且在return中指定返回的内容

  1. 多个返回值,返回值名称没有被使用

  1. return覆盖命名返回值,返回值名称没有被使用

package main

import "fmt"

func test() {
    fmt.Print("testing...")
}
func main() {
    test()
}
package main

import "fmt"

func test() (string, int) {
    name := "Y4y17"
    age := 24
    return name, age
}
func main() {
    name, age := test()
    fmt.Printf("name: %v\n", name)
    fmt.Printf("age: %v\n", age)
}
package main

import "fmt"

func test() (name string, age int) {
    name = "Y4y17"
    age = 24
    return		//相当于return name,age
}
func main() {
    name, age := test()
    fmt.Printf("name: %v\n", name)
    fmt.Printf("age: %v\n", age)
}
package main

import "fmt"

func test() (name string, age int) {
    n := "Y4y17"	//重新定义了n和a,那么返回的时候只能返回n和a,而不是name和age
    a := 24			//这种情况一般不这样写,一般就是直接去掉返回值中的name和age,只保留类型
    return n, a
}
func main() {
    name, age := test()
    fmt.Printf("name: %v\n", name)
    fmt.Printf("age: %v\n", age)
}
  1. Go中经常会使用其中一个返回值作为函数是否执行成功、是否有错误信息的判断条件;例如return value,exists、return value,ok、return value,err等

  1. 当函数的返回值过多的时候,例如有4个以上的返回值,应该将这些返回值收集到容器中,然后以返回容器的方式去返回。例如,同类型的返回值可以放进slice中,不同类型的返回值可以放进map中。

  1. 当函数有多个返回值的时候,如果其中某个或者是某几个返回值不想用,可以通过下划线_来丢弃这些返回值。

函数的参数

package main

import "fmt"

func test(a int) {
    a = 200	//test函数中修改变量a的值为200
}
func main() {
    a := 5	//定义变量a的值为5
    test(a)
    fmt.Printf("a: %v\n", a)//输出a的值,依然还是5
}

数组、切片、指针都是传地址,也就是传址的方式;

package main

import "fmt"

func test(s []int) {
    s[2] = 17
}
func main() {
    s := []int{1, 2, 3, 4}
    test(s)
    fmt.Printf("s: %v\n", s)//输出的结果为s: [1 2 17 4]
}

变长参数

package main

import "fmt"
//其实就像是传递了一个数组或者是切片
func test(args ...int) {
    for _, v := range args {
        fmt.Printf("v: %v\n", v)
    }
}
func main() {
    test(1, 2, 3, 4, 5, 6, 7)
}
package main

import "fmt"

func test(name string, b bool, args ...int) {
    fmt.Printf("name: %v\n", name)
    fmt.Printf("b: %v\n", b)
    for _, v := range args {
        fmt.Printf("v: %v\n", v)
    }
}
func main() {
    test("Y4y17", true, 1, 2, 3, 4, 5, 6, 7)
}

函数中的type关键字

相当于在c语言中的typedef关键字,说白了就是对现有的数据类型起了一个别名

package main

import "fmt"

func add(a int, b int) int {
    return a + b
}
func comp(a int, b int) int {
    if a > b {
        return a
    } else {
        return b
    }
}
func main() {
    type f func(a int, b int) int
    ff := add
    r := ff(1, 2)
    fmt.Printf("r: %v\n", r)
    ff = comp
    r = ff(1, 2)
    fmt.Printf("r: %v\n", r)
}

Go高阶函数

  1. 函数作为参数

package main

import "fmt"

func test(name string, f func(string)) {	
    f(name)
}
func sayHello(name string) {
    fmt.Printf("Hello: %v\n", name)
}
func main() {
    test("Y4y17", sayHello)
}

//test函数接受两个参数,分别是string类型的name和func(函数类型)的f(函数名)

sayHello函数接受一个参数,即string类型的name,主函数中调用test函数,传递参数Y4y17,和sayHello函数名;那么test函数中便会执行sayHello("Y4y17")

  1. 函数作为返回值

package main

import "fmt"

func add(a int, b int) int {
    return a + b
}
func sub(a int, b int) int {
    return a - b
}
func test(operate string) func(int, int) int {
    //test函数接受一个string类型的参数operate,test函数返回值是一个函数,该函数有两个int类型的参数并且返回值也是int类型
    
    switch operate {
    case "+":
        //当operate是+的时候,返回add方法
        return add
    case "-"://当operate是-的时候,返回sub方法
        return sub
    default:
        return nil
    }
}

func main() {
    f := test("-")
    res := f(1, 2)
    fmt.Printf("res: %v\n", res)
}

匿名函数

前面提到了在函数中是不允许嵌套函数的,但是我们可以使用匿名函数,来实现一些简单的功能:

package main

import "fmt"

func main() {
    //匿名函数和普通函数的区别其实就是没有了函数的名字,当在一个函数中不写函数名的时候就是匿名函数
    max := func(a int, b int) int {
        if a > b {
            return a
        } else {
            return b
        }
    }(1, 2)	//直接在最后面加上()以及实参的时候,就是自己调用自己
	//r := max(3, 8)	
	//fmt.Printf("r: %v\n", r)
	fmt.Printf("max: %v\n", max)
}

Golang闭包

闭包可以理解成定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁,或者是说函数和其引用环境的组合体

闭包指的是一个函数和与其相关的应用环境组合而成的实体。简单来说,闭包=函数+引用环境。看下面的例子:

package main

import "fmt"

//定义一个函数名为test,该函数返回值是一个函数,这个函数有一个int类型的参数 并且他返回值是一个int类型的数
func test() func(int) int {
    var x int
    return func(i int) int {
        x += i
        return x
    }
}
func main() {
    f := test()
    //f赋值为test的返回值,就是返回的函数,初始x为0
    fmt.Printf("f(10): %v\n", f(10))	//计算0+10=>10 这里x就变成了10 而不是0
    fmt.Printf("f(20): %v\n", f(20))	//计算10+20=>30 这里x就变成了30 而不是10
    fmt.Printf("f(30): %v\n", f(30))	//计算30+30=>60 这里x就变成了60 而不是30
}

变量f是一个函数并且他引用了其外部作用域中的x变量,此时f就是一个闭包。在f的生命周期内,变量x也一直有效;

package main

import (
    "fmt"
    "strings"
)

func makeSuffixFunc(suffic string) func(string) string {
    return func(name string) string {
        //这里的strings.HasSuff(name.suffic)表示判断name是否以suffic结尾
        //如果是返回true,否则false	需要导包strings
        if !strings.HasSuffix(name, suffic) {
            return name + suffic
        } else {
            return name
        }
    }
}
func main() {
    f := makeSuffixFunc("World")
    str := f("Hello")
    fmt.Printf("str: %v\n", str)
}
package main

import "fmt"

func cal(base int) (func(int) int, func(int) int) {
    add := func(a int) int {
        base += a
        return base
    }
    sub := func(a int) int {
        base -= a
        return base
    }
    return add, sub
}
func main() {
    add, sub := cal(10)
    res := add(10)
    fmt.Printf("res: %v\n", res)
    res = sub(5)
    fmt.Printf("res: %v\n", res)
}

定义了cal函数,cal函数存在一个形参base,cal函数返回值存在两个,并且这两个都是函数,之后在cal函数中定义两个匿名的函数分别赋值给add 和 sub,最终cal函数返回这两个匿名函数,之后在main函数中,令add sub为cal(10) ,其中base就是10 之后执行res=add(10),而这个10是匿名函数的形参a=10,执行base+=a故base=20

base的值会存储下来,之后res = sub(5),此时sub函数中的形参a就是5,再次执行base-=a,故得到base=15

Go语言中的递归函数

函数内部调用函数自身的函数称之为递归函数

使用递归函数最重要的三点:

  1. 递归就是自己调用自己

  1. 必须先定义函数的退出条件,没有退出条件,递归将成为死循环

  1. go语言递归函数很可能会产生一大堆的goroutine,也很可能会出现占空间内存溢出的问题

package main

import "fmt"

//数的阶乘
func fc(n int) int {
    if n <= 1 {
        return 1
    } else {
        res := n * fc(n-1)
        return res
    }
}
func main() {
    res := fc(5)
    fmt.Printf("res: %v\n", res)
}
package main

import "fmt"
//f(n)=f(n-1)+f(n-2) f(2)==f(1)==1
func fb(n int) int {
    if n <= 2 {
        return 1
    } else {
        res := fb(n-1) + fb(n-2)
        return res
    }
}
func main() {
    fmt.Printf("fb(3): %v\n", fb(3))
}

Go语言中的defer语句

go语言中的defer语句会将其后面跟随的语句进行延时处理,在defer归属的函数即将返回时,姜堰市处理的语句按defer定义的逆序进行执行;也就是说先被defer的语句最后被执行,最后被defer的语句,最先被执行

package main

import "fmt"

func main() {
    fmt.Printf("start...\n")
    defer fmt.Printf("stop1...\n")
    defer fmt.Printf("stop2...\n")
    defer fmt.Printf("stop3...\n")
    fmt.Printf("END...\n")
}

输出结果如下:

Go语言中的init函数

golang有一个特殊的函数init函数,先于main函数的执行,主要实现包级别的一些初始化操作

init函数额主要特点

  1. init函数先于main函数自动执行,不能被其他函数调用

  1. init函数没有输入参数、返回值

  1. 每个包可以有多个init函数

  1. 包的每个源文件也可以有多个init函数,这点比较特殊

  1. 同一个包的init执行顺序,golang没有明确的定义;

  1. 不同包的init函数按照包导入的依赖关系决定执行顺序

初始化顺序:变量初始化>init()>main()

package main

import "fmt"

var i int = initVar()

func initVar() int {
    fmt.Printf("initvar...\n")
    return 100
}
func init() {
    fmt.Printf("init2...\n")
}
func init() {
    fmt.Printf("init...\n")
}
func main() {
    fmt.Printf("start...\n")
}

输出结果为:

同时存在多个init()的时候,遵循自上而下的执行顺序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/368703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vulnhub靶场----7、DC-7

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-7下载地址&#xff1a;https://download.vulnhub.com/dc/DC-7.zip kali&#xff1a;192.168.144.148 DC-7&#xff1a;192.168.144.155 二、渗透流程 nmap -T5 -A -p- -sV -sT 192.168.144.155思路&#xff1a; …

【Opencv项目实战】目标检测:自动检测出现的所有动态目标

文章目录一、项目思路二、算法详解2.1、计算两个数组或数组与标量之间的每个元素的绝对差。2.2、轮廓检测 绘制物体轮廓 绘制矩阵轮廓2.3、连续窗口显示2.4、读取视频&#xff0c;显示视频&#xff0c;保存视频三、项目实战&#xff1a;实时动态目标检测实时动态目标检测一、…

[蓝桥杯 2018 省 A] 付账问题 贪心题

几个人一起出去吃饭是常有的事。但在结帐的时候&#xff0c;常常会出现一些争执。现在有 n 个人出去吃饭&#xff0c;他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是&#xff0c;所有人带的钱的总数是足够付账的&#xff0c;但现在问题来了&#xff1a;每个人分别要出…

Joomla未授权访问漏洞(CVE-2023-23752)

漏洞简介 ​ 在 Joomla! 版本为4.0.0 到 4.2.7中发现了一个漏洞&#xff0c;在Joomla受影响的版本中由于对Web服务端点的访问限制不当&#xff0c;远程攻击者可以绕过安全限制获得Web应用程序敏感信息。 影响版本 4.0.0 < Joomla < 4.2.7 环境搭建 文件下载地址 ht…

Python 函数式编程

函数式编程&#xff1a;允许把函数本身作为参数传入另一个函数&#xff0c;还允许返回一个函数&#xff01; 1.高阶函数 一个函数可以接收另一个函数作为参数&#xff0c;这种函数称之为高阶函数 abs(-10) 是函数调用 abs是函数本身 abs函数名其实是一个变量名 变量可以…

C++基础入门丨8. 结构体——还需要知道这些

Author&#xff1a;AXYZdong 硕士在读 工科男 有一点思考&#xff0c;有一点想法&#xff0c;有一点理性&#xff01; 定个小小目标&#xff0c;努力成为习惯&#xff01;在最美的年华遇见更好的自己&#xff01; CSDNAXYZdong&#xff0c;CSDN首发&#xff0c;AXYZdong原创 唯…

SpringCloud - Nacos注册发现

目录 服务注册到Nacos 服务分级存储模型 NacosRule负载均衡 服务实例的权重设置 环境隔离 Nacos与Eureka的对比 添加Nacos配置 微服务配置拉取 配置热更新 多环境配置共享 服务注册到Nacos 1.在父工程引入SpringCloudAlibaba的依赖 2.注释掉order-service和user-ser…

Web前端学习:一

编辑器的基础使用 编辑器推荐使用&#xff1a; HBuilderx&#xff08;免费中文&#xff09;&#xff08;建议使用&#xff09; Sublime&#xff08;免费英文&#xff09; Sublime中文设置方法&#xff0c;下载语言插件&#xff1a; 1、进入Sublime后&#xff0c;ShiftCtrlP…

流程图培训

工具 wps 目前咱们在新建里面&#xff0c;可以新建流程图 构成流程图的图形符号及其作用 常用的流程图介绍 flowchart 和 BPMN 两种 flowchart: 最开始的全名是”Process Flow Charts”&#xff0c;即处理流程图表。 BPMN&#xff1a; 定义了业务流程图&#xff0c;其基…

最新版本vue3+vite重构尚品汇(解决接口问题)第1-20集

本来想弄微信小程序的&#xff0c;但是注册小程序要花300块钱&#xff0c;我自学编程这么久&#xff0c;还没赚到1分钱呢。所以还是白嫖起手&#xff0c;从尚品汇弄起&#xff0c;弄完自己做一个实际的电商平台项目&#xff0c;把所有流程走一遍&#xff0c;到时候拿着自己的项…

JavaEE简单实例——MyBatis的一对一映射的嵌套查询的简单介绍和基础配置

简单介绍&#xff1a; 在前一章我们介绍了关于MyBatis的多表查询的时候的对应关系&#xff0c;其中有三种对应关系&#xff0c;分别是一对一&#xff0c;一对多&#xff0c;多对多的关系。如果忘记了这三种方式的对应形式可以去前面看看&#xff0c;一定要记住这三种映射关系的…

微服务架构下路由、多活、灰度、限流的探索与挑战

导语 2022腾讯全球数字生态大会已圆满落幕&#xff0c;大会以“数实创新、产业共进”为主题&#xff0c;聚焦数实融合&#xff0c;探索以全真互联的数字技术助力实体经济高质量发展。大会设有29个产品技术主题专场、18个行业主题专场和6个生态主题专场&#xff0c;各业务负责人…

Linux基础命令-locate快速查找文件

文章​​​​​​​目录 locate 命令介绍 语法格式 基本参数 参考实例 1&#xff09;查找1.txt相关的文件 2&#xff09;查找包含pass和txt都有的文件 3&#xff09;只匹配文件名&#xff0c;有路径的情况下不进行匹配 4&#xff09;匹配不区分大小写的文件 5&#…

Java多线程(四)---并发编程容器

1.经常使用什么并发容器&#xff0c;为什么&#xff1f;答&#xff1a;Vector、ConcurrentHashMap、HasTable一般软件开发中容器用的最多的就是HashMap、ArrayList&#xff0c;LinkedList &#xff0c;等等但是在多线程开发中就不能乱用容器&#xff0c;如果使用了未加锁&#…

Java EE|TCP/IP协议栈之TCP协议工作机制上

文章目录前言一、确认应答二、超时重传三、连接管理三次握手四次挥手前言 前边&#xff0c;我们已经大概交代了TCP的报文结构。但是仍有一些字段我们不确定到底怎么理解&#xff0c;这里就分析TCP的内部工作机制了。 TCP的内部很复杂&#xff0c;有很多机制&#xff0c;这里我们…

Super intelligent port AI smart port termial, CIMCAI top port AI

中国上海人工智能企业CIMCAI&#xff0c;全球港航人工智能领军者企业&#xff0c;顶尖AI科技及工业级成熟人工智能产品&#xff0c;打造高效能智能化港口数字化航运码头数字化。Ceaspectus™领跑全球港口人工智能&#xff0c;建设新一代高效能先进港口码头。Ceaspectus™先进方…

通过操作Cortex-A7核,串口输入相应的命令,控制LED灯进行工作

1.通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输入led2off,开饭led2灯熄灭 5.例如在串口输入led…

苹果电容笔和普通电容笔区别是什么?开学好用电容笔推荐

苹果的电容笔与一般的电容笔有何不同呢&#xff1f;两者的差距并不是很大。不过这款原装的苹果电容笔&#xff0c;重量要普通的电容笔重得多&#xff0c;而且笔尖还有一个特殊的重力感应装置&#xff0c;在其他方面两者并没有太大的差异。但是&#xff0c;由于苹果电容笔的售价…

QT自绘标题和边框

在QT中如果想要自绘标题和边框&#xff0c;一般步骤是&#xff1a; 1&#xff09; 在创建窗口前设置Qt::FramelessWindowHint标志&#xff0c;设置该标志后会创建一个无标题、无边框的窗口。 2&#xff09;在客户区域的顶部创建一个自绘标题栏。 3&#xff09;给窗口绘制一个背…

Hadoop的生成经验调优和基准测试

文章目录&#xff08;1&#xff09;项目经验之HDFS存储多目录&#xff08;2&#xff09;项目经验之集群数据均衡&#xff08;3&#xff09;项目经验之Hadoop参数调优&#xff08;4&#xff09;项目经验之支持LZO压缩配置&#xff08;5&#xff09;项目经验之LZO创建索引&#x…