go对参数的处理偏向保守:
- 不支持有默认值的可选参数,不支持命名实参
- 调用的时候必须按照签名顺序传递指定类型和数量的实参,就算以"_"命名的参数也不能忽略
- 参数可看作函数的局部变量,因此不能在相同层次定义同名变量
- 不管是指针,引用类型,还是其他类型参数,都是值拷贝传递,在函数调用前,会为形参和返回值分配内存空间,并将实参拷贝到形参内存
- 实现传出参数(out),通常建议使用返回值,也可以用二级指针
func test(p **int) { // 整型指针的地址 x := 100 // 变量x 为100 *p = &x // 整型指针指向x的地址 } func main() { var p *int test(&p) fmt.Println(*p) }
- 如果函数参数过多,建议将其重构为一个复合结构类型,也算是变相实现可选参数和命名实参功能
type serverOption struct { address string port int path string timeout time.Duration log *log2.Logger } func newOption() *serverOption { return &serverOption{ address: "0.0.0.0", port: 8080, path: "/func/test", timeout: time.Second * 5, log: nil, } } func server(option *serverOption) {} func main() { opt := newOption() opt.port = 8085 server(opt) }
变参:
- 本质上是一个切片,只能接受一到多个同类型参数,必须放在列表尾部
func test(s string, a ...int) { fmt.Printf("%T, %v\n", a, a) } func main() { test("abc", 1,2,3,4,5) }
- 将切片作为变参时,需进行展开操作,如果是数组,先将其转换成切片
func test(s string, a ...int) { fmt.Printf("%T, %v\n", a, a) } func main() { s := [5]int{1,2,3,4,5} test("abc", s[:]...) }
- 既然是切片,那么参数复制的仅是切片本身,并不包括底层数组,也因此可以修改原数据
func test( a ...int) { for i := range a{ a[i] += 200 } } func main() { a := []int{1, 2, 3, 4} test(a...) fmt.Println(a) }
知识补充:
- 形参,实参,可选参数,命名实参,传出参数区别