57 lines
2.4 KiB
Markdown
57 lines
2.4 KiB
Markdown
|
### 函数参数
|
|||
|
- 实际参数:函数实际调用时传入的参数
|
|||
|
- 形式参数:把参数列表中的参数
|
|||
|
![](https://blog-heysq-1255479807.cos.ap-beijing.myqcloud.com/blog/wiki/go/function.jpg)
|
|||
|
|
|||
|
### 传参
|
|||
|
- 函数参数传递采用是值传递的方式
|
|||
|
- 所谓“值传递”,就是将实际参数在内存中的表示逐位拷贝(Bitwise Copy)到形式参数中
|
|||
|
- 对于像整型、数组、结构体这类类型,它们的内存表示就是它们自身的数据内容,因此当这些类型作为实参类型时,值传递拷贝的就是它们自身,传递的开销也与它们自身的大小成正比
|
|||
|
- 像 string、切片、map 这些类型它们的内存表示对应的是它们数据内容的“描述符”。当这些类型作为实参类型时,值传递拷贝的也是它们数据内容的“描述符”,不包括数据内容本身,所以这些类型传递的开销是固定的,与数据内容大小无关
|
|||
|
|
|||
|
### 函数传参例外
|
|||
|
- 对于类型为接口类型的形参,Go 编译器会把传递的实参赋值给对应的接口类型形参
|
|||
|
- 对于为变长参数的形参,Go 编译器会将零个或多个实参按一定形式转换为对应的变长形参
|
|||
|
- 变长参数实际上是通过切片来实现
|
|||
|
|
|||
|
### Go函数特征
|
|||
|
- 多个可以命名的返回值
|
|||
|
- 函数可以存储在变量中
|
|||
|
- 支持在函数内创建并通过返回值返回
|
|||
|
- 可以作为参数传入函数
|
|||
|
- 拥有自己的类型`type HandlerFunc func(ResponseWriter, *Request)`
|
|||
|
|
|||
|
### 函数健壮性原则
|
|||
|
- 不要相信任何外部输入的参数
|
|||
|
- 不要忽略任何一个错误
|
|||
|
- 不要假定异常不会发生
|
|||
|
|
|||
|
### defer 获取调用函数方法名
|
|||
|
- runtime.Caller,参数为0时,返回调用者本身的信息(Trace的信息),为1是返回调用调用者的信息(调用Trace的信息)
|
|||
|
- Caller 函数有四个返回值:
|
|||
|
- 第一个返回值代表的是程序计数(pc)
|
|||
|
- 第二个和第三个参数代表对应函数所在的源文件名以及所在行数
|
|||
|
- 最后一个参数代表是否能成功获取这些信息
|
|||
|
- runtime.FuncForPC 函数和程序计数器(PC)得到被跟踪函数的函数信息
|
|||
|
```go
|
|||
|
|
|||
|
// trace1/trace.go
|
|||
|
|
|||
|
func Trace() func() {
|
|||
|
pc, _, _, ok := runtime.Caller(1)
|
|||
|
if !ok {
|
|||
|
panic("not found caller")
|
|||
|
}
|
|||
|
|
|||
|
fn := runtime.FuncForPC(pc)
|
|||
|
name := fn.Name()
|
|||
|
|
|||
|
println("enter:", name)
|
|||
|
return func() { println("exit:", name) }
|
|||
|
}
|
|||
|
|
|||
|
func main() {
|
|||
|
defer Trace()()
|
|||
|
foo()
|
|||
|
}
|
|||
|
```
|