函数生成包含函数的名字,形参列表,返回值列表(可选)以及函数体构成.数组
func name(parameter-list) (result-list) {
body
}
复制代码
须要注意一下几点:函数
函数的形参列表和返回值列表组成函数的签名,函数的签名会在函数被调用的时候作校验是否调用合法.spa
参数的传递是按值传递的.指针
支持多返回值.code
函数变量是有类型的,不符合函数签名类型的调用会报错对象
func changeArr(a [3]int) {
a[0] = 100
}
func getArr(a [3]int) (int, int) {
return a[0], a[1] // 多返回值
}
func main() {
test := [3]int{1,2,3}
changeArr(test)
fmt.Println(test[0]) // 1 数组是基本类型 值传递不会改变原数组
a, b := getArr(test); // 1, 2
}
// 当形参的基本类型的时候,不会修改外部的值.当形参是引用类型的时候,有可能会修改外部的值.
复制代码
经过在参数列表最后的类型名称以前使用省略号来声明一个变长函数声明.资源
func log(vals ...int) {
for _, value := range vals {
fmt.Println(value)
}
}
func main() {
b := []int{1,2,3}
log(b...) // 1, 2, 3
log(1,2,3) // 1, 2, 3
}
复制代码
经过在func关键字后不指定函数的名字能够声明函数变量,这种方式函数能获取整个词法环境(外部的变量).开发
func add() func() int {
var x int;
return func() int {
x++
return x
}
}
func main() {
f := add()
fmt.Println(f()) // 1
fmt.Println(f()) // 2
}
复制代码
go语言经过普通的值来报告错误.常规的错误是开发者能够预见而且决定错误的行为的.这样获得的错误信息因为没有相应的堆栈信息而更加清晰.get
调用者在调用函数发生错误的时候,在错误信息上添加更多的调用信息传递给上层.string
func test2()([]int, error) {
return nil, errors.New("test2")
}
func test1() ([]int, error) {
ret, err := test2()
if err != nil {
return nil, fmt.Errorf("test1 call test2 %v", err)
}
return ret, nil;
}
func main() {
_, err := test1()
fmt.Println(err); // test1 call test2 test2
}
复制代码
defer语句是普通的函数调用,defer语句能确保函数的return语句或函数执行完毕以后执行对应的defer函数.
func log() func() {
fmt.Println("start")
return func() { fmt.Println("end") }
}
func main() {
defer log()()
fmt.Println("test defer")
}
// 输出 start test defer end
复制代码
defer执行匿名函数会获取当前的词法环境,有可能修改函数执行的结果.
defer语句能保证函数执行完执行,某些状况会致使资源没法释放.
func readFills (filenams []string) {
for _, filename := range filenams {
f, err := os.Open(filename)
defer f.Close()
}
}
// 上面的例子会致使文件描述符被消耗没法释放,能够在进行单独的封装来控制defer对资源的释放.
复制代码
方法是声明特定类型(对象)上能够执行的函数. 一般能够使用以下的方式声明:
func (p structName) funcName(parameter-list) (result-list) {
body
}
// p 特定的类型(接受者) 声明能够在p类型上调用funcName的方法
复制代码
注意:
因为方法会复制实参,当须要方法的调用对外界产生影响的时候,就须要经过指针类型来完成方法的声明,以下面的例子:
type Point struct {
x, y int
}
func (p *Point) ScaleBy(factor int) {
p.x *= factor
p.y *= factor
}
func main() {
p := &Point{10, 10} // 获取指针
p.ScaleBy(2) // p{20, 20}
q := Point{1,2}
q.ScaleBy(3) // q{3,6} 当类型符合的时候,会进行隐式转换 至关于 (&q).ScaleBy(3)
}
复制代码
能够将一个特定类型的方法赋值给一个变量,这个变量称为方法变量.该方法变量已绑定到特定的接收者上(caller),经过传递形参就能够完成方法的调用.一般用于绑定特定的接受者.
type Point struct {
x, y int
}
func (p *Point) ScaleBy(factor int) {
p.x *= factor
p.y *= factor
}
func main() {
p := &Point{10, 10}
scaleBy := p.ScaleBy
scaleBy(2) // p{20, 20}
}
复制代码
type Point struct {
x, y int
}
func (p *Point) ScaleBy(factor int) {
p.x *= factor
p.y *= factor
}
func main() {
p := &Point{10, 10}
scaleBy := (*Point).ScaleBy // 方法表达式
scaleBy(p,2)
}复制代码