函数
参数
函数可以通过两种方式传递参数
- 值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
- 指针传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
**注意1:**无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低
**注意2:**map、slice、chan、指针、interface默认以引用的方式传递
不定参数
不定参数传值 就是函数的参数不是固定的,后面的类型是固定的
Golang 可变参数本质上就是 slice,只能有一个,且必须是最后一个
func myfunc(args ...int) { //0个或多个参数
}
func add(a int, args…int) int { //1个或多个参数
}
func add(a int, b int, args…int) int { //2个或多个参数
}
func myfunc(args ...interface{}) {
}
func test(s string, n ...int) string {
var x int
for _, i := range n {
x += i
}
return fmt.Sprintf(s, x)
}
func main() {
s := []int{1, 2, 3}
res := test("sum: %d", s...) // slice... 展开slice
println(res)
}
任意类型的不定参数: 就是函数的参数和每个参数的类型都不是固定的,用interface{}传递任意类型数据是Go语言的惯例用法,而且interface{}是类型安全的
返回值
命名返回参数允许 defer 延迟调用通过闭包读取和修改
package main
func add(x, y int) (z int) {
defer func() {
z += 100
}()
z = x + y
return
}
func main() {
println(add(1, 2))
}
运行结果
103
显式 return 返回前,会先修改命名返回参数
package main
func add(x, y int) (z int) {
defer func() {
fmt.Println("print in defer, z:", z)
}()
z = x + y
fmt.Println("return")
return z + 200 // 执行顺序: (z = z + 200) -> (call defer) -> (return)
}
func main() {
println(add(1, 2)) // 输出: 203
}
运行结果
return
print in defer, z: 203
203
方法
go的方法总是和定义的类型(结构体)绑定到一起,且隐式的将实例作为第一实参 (receiver),一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针
// 参数列表和返回值列表可以省略
func (recevier type) methodName(参数列表)(返回值列表){}
值类型和指针类型方法
package main
import "fmt"
type User struct {
Name string
}
// 方法
func (u User) valuePrint() {
fmt.Println("name: ", u.Name)
}
func (u User) valueSet() {
u.Name = "honghong"
}
// 方法
func (u *User) pointerPrint() {
fmt.Println("name: ", u.Name)
}
func (u *User) pointerSet() {
u.Name = "honghong"
}
func main() {
fmt.Println("hello world")
a := User{Name: "xiaoming"}
b := &User{Name: "xiaohong"}
fmt.Println("值方法(接受者为值时)")
a.valueSet()
a.valuePrint()
b.valueSet()
b.valuePrint()
fmt.Println("指针方法(接受者为指针时)")
a.pointerSet()
a.pointerPrint()
b.pointerSet()
b.pointerPrint()
}
运行结果
值方法(接受者为值时)
name: xiaoming
name: xiaohong
指针方法(接受者为指针时)
name: honghong
name: honghong
当方法的接受者不是一个指针时,该方法操作对应接受者的值的副本,即使使用指针实例调用方法,但是方法的接受者是值类型,所以方法内部操作还是对副本的操作,而不是指针操作,不会改变实例的内容
当方法的接受者是一个指针时,无论实例是值还是指针,方法都会对原实例进行操作