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

package math

func 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.Mutex
var 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"

 

太利于调试了。。。defer语句还是要细看。

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

gopl.io/ch5/defer2
func main() {
defer printStack()
f(3)
}
func printStack() {
var buf [4096]byte
n := runtime.Stack(buf[:], false)
os.Stdout.Write(buf[:n])
}
不能为一个结构体定义同名的字段名和方法名,有点奇怪。
 

函数指针:go里其实也是有函数指针的,下面用go语言实现表驱动模式。
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 main() {
fm := make(map[int]func(int, int) int)
fm[] = add
fm[] = sub
protocol :=
i :=
j :=
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 :=
p := &x
test(p)
}

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

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

golang笔记——函数与方法的更多相关文章

  1. golang学习笔记---函数、方法和接口

    函数:对应操作序列,是程序的基本组成元素. 函数有具名和匿名之分:具名函数一般对应于包级的函数,是匿名函数的一种特例,当匿名函数引用了外部作用域中的变量时就成了闭包函数,闭包函数是函数式编程语言的核心 ...

  2. golang学习笔记--函数和方法

    在go中,函数类型是一等类型,这意味着可以吧函数当做一个值来传递和使用. func divide(dividend int,divisor int)(int,error){ //省略部分代码 } 参数 ...

  3. golang 函数和方法

    由于自己是搞python开发的,所以在学习go时,当看到函数和方法时,顿时还是挺蒙的,因为在python中并没有明显的区别,但是在go中却是两个完全不同的东西.在官方的解释中,方法是包含了接收者的函数 ...

  4. opencv-学习笔记(1)常用函数和方法。

    opencv-学习笔记(1)常用函数和方法. cv2.imread(filename,falg) filename是文件名字 flag是读入的方式 cv2.MREAD_UNCHANGED :不进行转化 ...

  5. Go语言学习笔记(7)——函数和方法

    Go语言中同时有函数和方法! 函数: go程序必须要包含一个main函数.main函数不能有任何参数和返回值! 1. 定义方法示例: func max(num1, num2 int) int { // ...

  6. Golang 函数以及函数和方法的区别

    在接触到go之前,我认为函数和方法只是同一个东西的两个名字而已(在我熟悉的c/c++,python,java中没有明显的区别),但是在golang中者完全是两个不同的东西.官方的解释是,方法是包含了接 ...

  7. 学习笔记:jquery1.9版本后废弃的函数和方法

    jQuery1.9+ 废弃的函数和方法 升级Jquery版本遇到的问题 (转载自:http://www.ppblog.cn/jquery1-9live.html  版权归原作者所有) jQuery1. ...

  8. GOLANG 匿名函数笔记

    在函数内部,没有名字的函数,就是匿名函数 实现方法1: func main(){ a := "我是无参无返回值的匿名函数" x := func(){ //可以获取到匿名函数外部的变 ...

  9. Golang笔记(二)面向对象的设计

    Golang笔记(二)面向对象的设计 Golang本质还是面向过程的语言,但它实现了一些OOP的特性,包括抽象.封装.继承和多态. 抽象和封装 Golang和C语言一样以struct为数据结构核心,不 ...

随机推荐

  1. [bootsrap]模态框使用例

    <a href="#modal1" role="button" class="btn btn-primary btn-sm" data ...

  2. 数据处理之PostgreSQL过程语言学习

    前段时间,公司更换新的PostgreSQL数据集市的系统过程中,自己下载了postgresqlAPI的pdf文件研究了一下PostgreSQL数据集市.发现使用PostgreSQL过程语言可以大大加快 ...

  3. java笔记

    ANT概述:http://www.blogjava.net/amigoxie/archive/2007/11/09/159413.html http://baitai.iteye.com/blog/7 ...

  4. MIT研发的新型匿名网络Riffle,下一个Tor

    现在的隐私问题是一个网络热词,如果你担心你上网的隐私会泄露,最有效的解决办法就是使用Tor.这款免费的匿名通信软件,能够让人们在与其他人通信时隐藏自己真实的信息. 虽然Tor是一个很好的匿名网络系统, ...

  5. NOIP2012国王游戏

      题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在 ...

  6. Winform listview控件、 容器控件

    1.常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2) GridLines:设置行和列之间是否显示网格 ...

  7. webService获取电话号归属地和获取天气情况步骤,及创建属于自己的webservice

    一.什么是Web服务 Web服务是一种可以用来解决跨网络应用集成问题的开发模式,目的是保证不同平台的应用服务可以互操作 二.Web服务的三个核心 Soap: SOAP(Simple Object Ac ...

  8. 用于部署war并重启Tomcat的脚本

    只需要定义两个变量, 一个是目标tomcat实例的目录, 另一个是war包的名称 # Please define the absolute path of tomcat instance THIS_T ...

  9. BBR拥塞控制算法

    BBR拥塞控制算法是Google最新研发的单边TCP拥塞控制算法Linux 内核4.9 已引入这个BBR算法,本人在CAC测试Ubuntu 14.04 安装Linux 4.9内核,延迟优化效果和TCP ...

  10. JS系列——Linq to js使用小结

    前言:前面几篇介绍了下C#基础技术中的几个:反射.特性.泛型.序列化.扩展方法.Linq to Xml等,本来还有两三个知识点没有写完,比如委托.多线程.异步等,后面会陆续将它们补起来,以便作为一套完 ...