侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

go语言中函数与方法介绍

Go  /  管理员 发布于 5年前   462

如果你遇到没有函数体的函数声明,表示该函数不是以Go实现的。

package mathfunc Sin(x float64) float //implemented in assembly language

如果为函数的每一个返回值都设置变量名,则会以相应的零值初始化,且在该函数的return语句中省略操作数,这种用法称之为 bare return。

go中的错误处理,习惯上是先进行一系列的初始化检查,将处理失败逻辑的代码先行处理,然后才是函数的实际逻辑,这样使得代码更简洁,避免过多的层级结构。

函数定义时,可以使用函数类型作为参数,也可以作为返回类型,是不是有点类似委托,从而实现闭包。此外还有匿名函数,是不是类似于lambda表达式。strings.Map 函数可以拿来试验。

func squares() func() int {    var x int    return func() int {        x++        return x * x    }}func main() {    f := squares()    fmt.Println(f()) // "1"    fmt.Println(f()) // "4"    fmt.Println(f()) // "9"    fmt.Println(f()) // "16"}

匿名函数和squares中,存在变量引用。这就是函数值属于引用类型和函数值不可比较的原因。Go使用闭包(closures)技术实现函数值,Go程序员也把函数值叫做闭包。

注意golang圣经中匿名函数一节中的例子程序。

go语言的可变参函数非常好用,你可以传递多个同类型参数,也可以直接传入一个该类型的切片(注意传入切片时要使用...标记,我想应该是为了同切片参数区分吧,毕竟两者还是有些不同的),如果想要使用不同类型的变参,那么使用万能的 interfac{} ,函数体内像解析切片一样解析这个变参就好了。

直到包含该defer语句的函数执行完毕时,defer后的函数才会被执行,不论包含defer语句的函数是通过return正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反

var mu sync.Mutexvar m = make(map[string]int)func lookup(key string) int {    mu.Lock()    defer mu.Unlock()    return m[key]}

调试复杂程序时,defer机制也常被用于记录何时进入和退出函数。

func bigSlowOperation() {    defer trace("bigSlowOperation")() // don't forget the    extra parentheses    // ...lots of work…    time.Sleep(10 * time.Second) // simulate slow    operation by sleeping}func trace(msg string) func() {    start := time.Now()    log.Printf("enter %s", msg)    return func() {         log.Printf("exit %s (%s)", msg,time.Since(start))     }}

我们只需要首先命名double的返回值,再增加defer语句,我们就可以在double每次被调用时,输出参数以及返回值。

func double(x int) (result int) {    defer func() { fmt.Printf("double(%d) = %d\n", x,result) }()    return x + x}_ = double(4)// Output:// "double(4) = 8"

为了方便诊断问题,runtime包允许程序员输出堆栈信息。在下面的例子中,我们通过在main函数中延迟调用printStack输出堆栈信息。

gopl.io/ch5/defer2func main() {    defer printStack()    f(3)}func printStack() {    var buf [4096]byte    n := runtime.Stack(buf[:], false)    os.Stdout.Write(buf[:n])}

不能为一个结构体定义同名的字段名和方法名,有点奇怪。

函数指针:go里其实也是有函数指针的,下面用go语言实现表驱动模式。

package mainimport (    "fmt")func add(a int, b int) int {    return a + b }func sub(a int, b int) int {    return a - b }func main() {    fm := make(map[int]func(int, int) int)    fm[1001] = add     fm[1002] = sub     protocol := 2001    i := 1    j := 2    if func_handle, ok := fm[protocol]; ok {        println(func_handle(i, j))     } else {        fmt.Printf("protocol: %d not register!", protocol)    }   }

返回局部变量指针:

不同于 C 语言,GO 的函数可以返回局部变化指针,且编译器会通过逃逸分析(escape analysis)来决定是否在堆上分配内存。

编译时可以通过 -gcflags "-l -m" 参数来禁用函数内联,函数内联会对内存分配有一些影响,具体不清楚。

函数参数没有所谓的引用传递,都是值传递的,区别只是传递的是拷贝对象还是指针而已。在 C 语言中,一般推荐传递指针参数来避免复制对象提升效率。

但在 go 中,被复制的指针会延长目标对象的生命周期,还可能导致它被分配到堆上,则性能消耗要加上堆内存分配和垃圾回收的成本,而在栈上复制小对象其实非常快,所以如果不是特别大的对象或确实需要修改原对象,一般不需要传指针参数。在并发编程中,也提倡使用不可变对象(只读或复制),可以消除数据同步的麻烦。

如下就会在堆上分配内存,编译时通过 -gcflags "-m" 可查看汇编代码:

func test(p *int) {    go func() {        println(p)    }() }func main() {    x := 100     p := &x    test(p)}

使用传出参数,推荐使用返回值,也可以使用二级指针:

func test(p **int) {    x := 100    *p = &x}func main() {    var p *int    test(&p)    println(*p)}

更多go语言知识请关注go语言教程栏目。

以上就是go语言中函数与方法介绍的详细内容,更多请关注其它相关文章!


  • 上一条:
    从go语言闭包谈函数式编程
    下一条:
    Go语言的内存模型介绍
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2017-09
    • 2020-03
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-12
    • 2021-01
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-08
    • 2024-11
    • 2025-02
    • 2025-04
    • 2025-05
    • 2025-06
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客