Go学习笔记函数部分

练习 6.1 mult_returnval.go

编写一个函数,接收两个整数,然后返回它们的和、积与差。编写两个版本,一个是非命名返回值,一个是命名返回值。

package main
import (
    "fmt";
    //"strings"
)
func fmm(a ,b int)(int, int ,int ){
    return a+b,a*b,a-b
}
func mm(a ,b int)(sum,ji,minus int){
    sum=a+b
    ji=a*b
    minus=a-b
    return 
}
func main() {
    a,b,c:=fmm(1,2)
    fmt.Print(a,b,c,"\n")
    a,b,c=mm(1,2)
    fmt.Print(a,b,c,"\n")
}
练习 6.2 error_returnval.go

编写一个名字为 MySqrt() 的函数,计算一个 float64 类型浮点数的平方根,如果参数是一个负数的话将返回一个错误。编写两个版本,一个是非命名返回值,一个是命名返回值。

package main
import (
    "fmt";
    //"strings"
)
func abs(a float64 )float64{
    if a>0{
        return a
    }else{
        return -a
    }
}
func MySqrt_fmm(a float64)(float64,bool){
    if(a<0){
        return 0,false
    }else{
        var start float64 =0
        var end float64 =a
        var mid float64 =(start+end)/2
        for (abs(mid*mid-a))>0.001{
            if mid*mid>a{
                end=mid
                mid=(start+end)/2
            }else{
                start=mid
                mid=(start+end)/2
            }
            
        }
        return mid,true
    }
}
func MySqrt_mm(a float64)(mid float64, ok bool){
    if(a<0){
        mid =0
        ok=false
        return mid,ok
    }else{
        var start float64 =0
        var end float64 =a
        mid  =(start+end)/2
        for (abs(mid*mid-a))>0.001{
            if mid*mid>a{
                end=mid
                mid=(start+end)/2
            }else{
                start=mid
                mid=(start+end)/2
            }
            
        }
        
        ok=true
        return mid,ok
    }
}
func main() {
    var shu float64=5.0
    a,b:=MySqrt_fmm(shu)
    if b{
        fmt.Print(a,b,"\n")
    }
    c,d:=MySqrt_fmm(shu)
    if d{
        fmt.Print(c,d,"\n")
    }
    
}
传递变长参数

如果函数的最后一个参数是采用 …type 的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变参函数。

func myFunc(a, b, arg ...int) {}

示例函数和调用:

func Greeting(prefix string, who ...string)
Greeting("hello:", "Joe", "Anna", "Eileen")

在 Greeting() 函数中,变量 who 的值为 []string{“Joe”, “Anna”, “Eileen”}。

练习 6.3 varargs.go

写一个函数,该函数接受一个变长参数并对每个元素进行换行打印。

package main

import (
	"fmt"
)

func print(juzi ...string) (ok bool) {
	if len(juzi) == 0 {
		ok = false
	} else {
		for i := 0; i < len(juzi); i++ {
			fmt.Printf(juzi[i], "\n")
		}
		ok = true
	}
	return
}
func main() {
	print("fdfs", "adasda", "adasdasd", "dadasdad")
}

(等学到切片了用切片当参数试一下)

defer

关键字 defer 允许我们推迟到函数返回之前(或任意位置执行 return 语句之后)一刻才执行某个语句或函数(为什么要在返回之后才执行这些语句?因为 return 语句同样可以包含一些操作,而不是单纯地返回某个值)。
当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出):
例子1:

func f() {
	for i := 0; i < 5; i++ {
		defer fmt.Printf("%d ", i)
	}
}

上面的代码将会输出:4 3 2 1 0。
例子2:

package main

import "fmt"

func trace(s string)   { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }

func a() {
	trace("a")
	defer untrace("a")
	fmt.Println("in a")
}

func b() {
	trace("b")
	defer untrace("b")
	fmt.Println("in b")
	a()
}

func main() {
	b()
}
entering: b
in b
entering: a
in a
leaving: a
leaving: b
内置函数

在这里插入图片描述

递归函数
练习 6.4 fibonacci2.go

重写本节中生成斐波那契数列的程序并返回两个命名返回值(详见第 6.2 节),即数列中的位置和对应的值,例如 5 与 4,89 与 10。

package main

import (
	"fmt"
)
func fibonacci2(vua_1, idx_1, vua_2, idx_2 int) (vua_r, idx_r int) {
	if idx_2 == 2 {
		idx_r = idx_2 + 1
		vua_r = vua_2 + vua_1
		fmt.Print(idx_1, ":", vua_1, "\n")
		fmt.Print(idx_2, ":", vua_2, "\n")
		fibonacci2(vua_2, idx_2, vua_r, idx_r)
		return
	} else if idx_2 < 10 {
		idx_r = idx_2 + 1
		vua_r = vua_2 + vua_1
		fmt.Print(idx_2, ":", vua_2, "\n")
		fibonacci2(vua_2, idx_2, vua_r, idx_r)
		return
	} else {
		return
	}
}
func main() {
	fibonacci2(1, 1, 1, 2)
}
练习 6.5 10to1_recursive.go

使用递归函数从 10 打印到 1。

package main

import "fmt"

func pri1210(i int) {
	if i <= 10 {
		pri1210(i + 1)
		fmt.Print(i)
		return
	}
}
func main() {
	pri1210(1)
}
练习 6.6 factorial.go

实现一个输出前 30 个整数的阶乘的程序。

n 的阶乘定义为:n! = n * (n-1)!, 0! = 1,因此它非常适合使用递归函数来实现。
然后,使用命名返回值来实现这个程序的第二个版本。

特别注意的是:使用 int 类型最多只能计算到 12 的阶乘,因为一般情况下 int 类型的大小为 32 位,继续计算会导致溢出错误。那么,如何才能解决这个问题呢?

package main

import (
	"fmt"
)

func jiecheng(i int64, idx int64) {
	if idx <= 30 {
		fmt.Print(idx, ":", i, "\n")
		idx = idx + 1
		i = i * idx
		jiecheng(i, idx)
		return
	}

}
func main() {
	jiecheng(1, 1)
}

(学到big包尝试一下目前只能求的前20个的阶乘)
在这里插入图片描述

将函数作为参数
练习 6.7 strings_map.go

包 strings 中的 Map() 函数和 strings.IndexFunc() 一样都是非常好的使用例子。请学习它的源代码并基于该函数书写一个程序,要求将指定文本内的所有非 ASCII 字符替换成问号 ‘?’ 或空格 ’ '。您需要怎么做才能删除这些字符呢?

package main

import (
	"fmt"
)

func pan(rune1 rune) bool {
	if rune1 <= 255 && rune1 >= 0 {
		return true
	} else {
		return false
	}
}

func ss(pan func(int32) bool, s string) string {
	ss := []rune(s)
	for i, c := range ss {
		if pan(c) {
			continue
		} else {
			ss[i] = '?'
		}

	}
	res := string(ss)
	return res
}
func main() {
	s := "asdas阿松大短裤sadasd"
	k := ss(pan, s)
	fmt.Print(k)
}

(数据类型这块不熟悉,晕晕晕…)

匿名函数(闭包)

匿名函数同样被称之为闭包(函数式语言的术语):它们被允许调用定义在其它环境下的变量。闭包可使得某个函数捕捉到一些外部状态,例如:函数被创建时的状态。另一种表示方式为:一个闭包继承了函数所声明时的作用域。这种状态(作用域内的变量)都被共享到闭包的环境中,因此这些变量可以在闭包中被操作,直到被销毁,

练习 6.8

在 main() 函数中写一个用于打印 Hello World 字符串的匿名函数并赋值给变量 fv,然后调用该函数并打印变量 fv 的类型。

package main

import (
	"fmt"
	"reflect"
)

func main() {
	fv := func() { fmt.Print("hello world\n") }
	fv()
	fmt.Print(reflect.TypeOf(fv), "\n")
	fmt.Print(fv)
}

在这里插入图片描述
fv是一个地址指向匿名函数

函数作为返回值
练习 6.9 fibonacci_closure

不使用递归但使用闭包改写第 6.6 节中的斐波那契数列程序。

package main

func fibonacci_closure() func(a int) int {
	var x int
	var y int
	return func(a int) int {
		if a == 1 {
			x = 1
			return x
		} else if a == 2 {
			y = 1
			return y
		} else {
			temp := y
			y = x + y
			x = temp
			return y
		}
	}
}
func main() {
	y := fibonacci_closure()
	for i := 1; i <= 10; i++ {
		x := y(i)
		print(x, "\n")
	}
}
使用闭包调试

当您在分析和调试复杂的程序时,无数个函数在不同的代码文件中相互调用,如果这时候能够准确地知道哪个文件中的具体哪个函数正在执行,对于调试是十分有帮助的。您可以使用 runtime 或 log 包中的特殊函数来实现这样的功能。包 runtime 中的函数 Caller() 提供了相应的信息,因此可以在需要的时候实现一个 where() 闭包函数来打印函数执行的位置

where := func() {
	_, file, line, _ := runtime.Caller(1)
	log.Printf("%s:%d", file, line)
}
where()
// some code
where()
// some more code
where()

您也可以设置 log 包中的 flag 参数来实现:

log.SetFlags(log.Llongfile)
log.Print("")

或使用一个更加简短版本的 where() 函数:

var where = log.Print
func func1() {
where()
... some code
where()
... some code
where()
}
计算函数执行时间

有时候,能够知道一个计算执行消耗的时间是非常有意义的,尤其是在对比和基准测试中。最简单的一个办法就是在计算开始之前设置一个起始时间,再记录计算结束时的结束时间,最后计算它们的差值,就是这个计算所消耗的时间。想要实现这样的做法,可以使用 time 包中的 Now() 和 Sub() 函数:

start := time.Now()
longCalculation()
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值