Post Views: 84
函数只能判断其是否为nil,不支持其他比较操作 func a() {}
func b() {}
func main() {
println(a == nil)
println(b == a) //无效操作
}
从函数返回局部变量指针是安全的,编译器通过逃逸分析(escape analysis)来决定是否在堆上分配内存 func test() *int {
a := 0x100
return &a
}
func main() {
var a *int = test()
println(a, *a)
}
4.2 参数 不管是指针,引用类型,还是其他类型参数,都是值拷贝传递。区别无非是拷贝目标对象,还是拷贝指针而已。 在函数调用前,会为形参和返回值分配内存空间。 变参本质上就是一个切片,只能接收一到多个同类型参数。且必须放在列表尾部。 func test(s string, a ...int) {
fmt.Printf("%T,%v\n", a, a)
}
func main() {
test("abc", 1, 2, 3, 4)
}
将切片作为变参时,须进行展开操作。 func test(a ...int) {
fmt.Println(a)
}
func main() {
a := [3]int{10, 20, 30}
test(a[:]...) //转换为slice后展开
}
4.3 返回值 有返回值的函数,必须有明确的return终止语句, 除非有panic,或者无break的死循环,则无须return终止语句 4.4 匿名函数 直接执行 func main() {
func(s string) {
println(s)
}("hello world!")
}
赋值给变量 func main() {
add := func(x, y int) int {
return x + y
}
println(add(1,2))
}
作为参数 func test(f func()) {
f()
}
func main() {
test(func(){
println("hello, world!")
})
}
作为返回值 func test() func(int, int) int {
return func(x, y int) int {
return x + y
}
}
func main() {
add := test()
println(add(1,2))
}
普通函数和匿名函数都可作为结构体字段,或经通道传递 func testStruct() {
type calc struct {
mul func(x, y int) int
}
x := calc{
mul:func(x, y int) int {
return x * y
},
}
println(x.mul(2,3))
}
func testChannel() {
c := make(chan func(int,int) int, 2)
c <- func(x, y int) int {
return x + y
}
println((<-c)(1,2))
}
不曾使用的匿名函数会被编译器当作错误 4.5 延迟调用 语句defer向当前函数注册稍后执行的函数调用。这些调用被称作延迟调用,因为它们直到当前函数执行线束才被执行。常用于资源释放,解除锁定,以及错误处理等操作 多个延迟注册按FILO次序执行 func main() {
defer println("a")
defer println("b")
}
/*
b
a
*/
编译器通过插入额外的指令来实现延迟调用执行,而return和panic语句都会终止当前函数流程,引发延迟调用。 相比直接用CALL汇编指令调用函数,延迟调用则须花费更大的代价。这其中包括注册、调用等操作。还有额外的缓存开销。 4.6 错误处理 官方推荐的标准做法是返回error状态 func Scanln(a ...interface{}) (n int, err error)
标准库将error定义为接口类型,以便实现自定义错误类型 type error interface {
Error() string
}
按惯例,error总是最后一个返回参数。 var errDivByZero = errors.New("division by zero")
func div(x, y int) (int, error) {
if y == 0 {
return 0, errDivByZero
}
return x / y, nil
}
func main() {
z, err := div(5, 0)
if err == errDivByZero {
log.Fatalln(err)
}
println(z)
}
与errors.New类似的还有fmt.Errorf,它返回一个格式化内容的错误对象 自定义错误 type DivError struct { //自定义错误类型
x, y int
}
func (DivError) Error() string { //实现error接口方法
return "division by zero"
}
func div(x, y int) (int, error) {
if y == 0 {
return 0, DivError(x, y) //返回自定义错误类型
}
return x / y, nil
}
func main() {
z, err := div(5, 0)
if err != nil {
switch e := err.(type) { //根据类型匹配
case DivError:
fmt.Println(e, e.x, e.y)
default:
fmt.Println(e)
}
log.Fatalln(err)
}
println(z)
}
panic,recover 接近try/catch结构化异常 内置函数,非语句 func panic(v interface{})
func recover() interface{}
panic会立即中断当前函数流程,执行延迟调用。在延迟调用函数中,recover可捕获并返回panic提交的错误对象 package main
import "log"
func main() {
defer func() {
if err := recover(); err != nil { //捕获错误
log.Fatalln(err)
}
}()
panic("i an dead") //引发错误
println("exit.") //永不会执行
}
连续调用panic 仅最后一个会被recover捕获, recover必须在延迟调用函数中执行才能正常工作
文章导航